@stfrigerio/sito-template 0.1.7 → 0.1.9

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 (26) hide show
  1. package/dist/components/atoms/ArrayInput/ArrayInput.d.ts +5 -0
  2. package/dist/components/atoms/ArrayInput/ArrayInput.d.ts.map +1 -1
  3. package/dist/components/atoms/Toggle/Toggle.d.ts +4 -0
  4. package/dist/components/atoms/Toggle/Toggle.d.ts.map +1 -1
  5. package/dist/components/atoms/Toggle/Toggle.stories.d.ts +1 -0
  6. package/dist/components/atoms/Toggle/Toggle.stories.d.ts.map +1 -1
  7. package/dist/components/molecules/SearchBar/SearchBar.d.ts +11 -2
  8. package/dist/components/molecules/SearchBar/SearchBar.d.ts.map +1 -1
  9. package/dist/components/molecules/SearchBar/index.d.ts +1 -1
  10. package/dist/components/molecules/SearchBar/index.d.ts.map +1 -1
  11. package/dist/components/molecules/Tabs/Tabs.d.ts +11 -5
  12. package/dist/components/molecules/Tabs/Tabs.d.ts.map +1 -1
  13. package/dist/components/molecules/index.d.ts +2 -2
  14. package/dist/components/molecules/index.d.ts.map +1 -1
  15. package/dist/components/organisms/charts/PieChart/PieChart.d.ts +2 -0
  16. package/dist/components/organisms/charts/PieChart/PieChart.d.ts.map +1 -1
  17. package/dist/components/organisms/charts/QuantifiableHabitsChart/QuantifiableHabitsChart.d.ts.map +1 -1
  18. package/dist/components/organisms/charts/SunburstChart/SunburstChart.d.ts +2 -0
  19. package/dist/components/organisms/charts/SunburstChart/SunburstChart.d.ts.map +1 -1
  20. package/dist/index.esm.js +182 -46
  21. package/dist/index.esm.js.map +1 -1
  22. package/dist/index.js +182 -46
  23. package/dist/index.js.map +1 -1
  24. package/dist/styles.css +1 -1
  25. package/dist/styles.css.map +1 -1
  26. package/package.json +1 -1
package/dist/index.esm.js CHANGED
@@ -198,7 +198,7 @@ function TextInput({ label, value, onChange, type = "text", onFocus, onBlur, pla
198
198
  return (jsxs("div", { className: getContainerClassName(), children: [jsxs("label", { htmlFor: inputId, children: [label, required && jsx("span", { className: styles$l.required, children: "*" })] }), jsxs("div", { style: { position: 'relative' }, children: [icon && jsx("div", { className: styles$l.inputIcon, children: icon }), jsx("input", { id: inputId, type: type, value: value, onChange: (e) => onChange(e.target.value), onFocus: onFocus, onBlur: onBlur, placeholder: placeholder, className: error ? styles$l.inputError : '', "aria-invalid": !!error, "aria-describedby": error ? `${inputId}-error` : undefined, disabled: disabled || loading, maxLength: maxLength, autoComplete: autoComplete }), actionButton && (jsx("button", { type: "button", className: styles$l.actionButton, onClick: actionButton.onClick, disabled: disabled || loading, children: actionButton.label }))] }), error && (jsx("span", { id: `${inputId}-error`, className: styles$l.errorMessage, children: error }))] }));
199
199
  }
200
200
 
201
- var styles$k = {"arrayInput":"ArrayInput-module_arrayInput__FNrd2","arrayInputLabel":"ArrayInput-module_arrayInputLabel__7Rpkj","arrayInputItem":"ArrayInput-module_arrayInputItem__eSH-6","inputWrapper":"ArrayInput-module_inputWrapper__i-MB-","input":"ArrayInput-module_input__792ru","complexItem":"ArrayInput-module_complexItem__iX3v6","fieldsWrapper":"ArrayInput-module_fieldsWrapper__fzqvn"};
201
+ var styles$k = {"arrayInput":"ArrayInput-module_arrayInput__FNrd2","arrayInputLabel":"ArrayInput-module_arrayInputLabel__7Rpkj","arrayInputItem":"ArrayInput-module_arrayInputItem__eSH-6","inputWrapper":"ArrayInput-module_inputWrapper__i-MB-","input":"ArrayInput-module_input__792ru","complexItem":"ArrayInput-module_complexItem__iX3v6","fieldsWrapper":"ArrayInput-module_fieldsWrapper__fzqvn","removeButton":"ArrayInput-module_removeButton__khhdR","addButton":"ArrayInput-module_addButton__10o-9"};
202
202
 
203
203
  /**
204
204
  * ArrayInput component - Versatile dynamic list manager
@@ -238,7 +238,7 @@ function ArrayInput(props) {
238
238
  return jsx(SimpleArrayInput, { ...props });
239
239
  }
240
240
  // Simple string array implementation
241
- function SimpleArrayInput({ label, values, onChange, placeholder }) {
241
+ function SimpleArrayInput({ label, values, onChange, placeholder, itemStyle, inputStyle }) {
242
242
  const handleChange = (index, value) => {
243
243
  const newValues = [...values];
244
244
  newValues[index] = value;
@@ -251,10 +251,14 @@ function SimpleArrayInput({ label, values, onChange, placeholder }) {
251
251
  const newValues = values.filter((_, i) => i !== index);
252
252
  onChange(newValues);
253
253
  };
254
- return (jsxs("div", { className: styles$k.arrayInput, children: [jsx("h3", { className: styles$k.arrayInputLabel, children: label }), values.map((value, index) => (jsxs("div", { className: styles$k.arrayInputItem, children: [jsx("div", { className: styles$k.inputWrapper, children: jsx("input", { type: "text", value: value, onChange: (e) => handleChange(index, e.target.value), placeholder: placeholder, className: styles$k.input }) }), jsx(Button, { variant: "ghost", size: "small", onClick: () => handleRemove(index), children: "Remove" })] }, `item-${index}`))), jsxs(Button, { variant: "primary", size: "small", onClick: handleAdd, children: ["Add ", label] })] }));
254
+ return (jsxs("div", { className: styles$k.arrayInput, children: [jsx("h3", { className: styles$k.arrayInputLabel, children: label }), jsx("div", { children: jsx(AnimatePresence, { children: values.map((value, index) => (jsxs(motion.div, { className: styles$k.arrayInputItem, style: itemStyle, initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0 }, transition: {
255
+ duration: 0.3,
256
+ ease: "easeInOut",
257
+ layout: { duration: 0.2 }
258
+ }, children: [jsx("div", { className: styles$k.inputWrapper, children: jsx("input", { type: "text", value: value, onChange: (e) => handleChange(index, e.target.value), placeholder: placeholder, className: styles$k.input, style: inputStyle }) }), jsx(Button, { variant: "ghost", size: "small", onClick: () => handleRemove(index), "aria-label": "Remove item", className: styles$k.removeButton, children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) })] }, `item-${index}`))) }) }), jsxs(Button, { variant: "primary", size: "small", onClick: handleAdd, className: styles$k.addButton, children: ["Add ", label] })] }));
255
259
  }
256
260
  // Complex object array implementation
257
- function ComplexArrayInput({ label, values, onChange, fields, getKey }) {
261
+ function ComplexArrayInput({ label, values, onChange, fields, getKey, itemStyle, inputStyle }) {
258
262
  const handleChange = (index, field, value) => {
259
263
  const newValues = [...values];
260
264
  newValues[index] = { ...newValues[index], [field]: value };
@@ -276,7 +280,11 @@ function ComplexArrayInput({ label, values, onChange, fields, getKey }) {
276
280
  // Generate key from all field values
277
281
  return fields.map(f => item[f.name] || '').join('-') + `-${index}`;
278
282
  };
279
- return (jsxs("div", { className: styles$k.arrayInput, children: [jsx("h3", { className: styles$k.arrayInputLabel, children: label }), values.map((value, index) => (jsxs("div", { className: `${styles$k.arrayInputItem} ${fields.length > 1 ? styles$k.complexItem : ''}`, children: [jsx("div", { className: styles$k.fieldsWrapper, children: fields.map((field) => (jsx(TextInput, { value: value[field.name] || '', onChange: (newValue) => handleChange(index, field.name, newValue), label: field.label, type: field.type, placeholder: field.placeholder }, field.name))) }), jsx(Button, { variant: "ghost", size: "small", onClick: () => handleRemove(index), children: "Remove" })] }, generateKey(value, index)))), jsxs(Button, { variant: "primary", size: "small", onClick: handleAdd, children: ["Add ", label] })] }));
283
+ return (jsxs("div", { className: styles$k.arrayInput, children: [jsx("h3", { className: styles$k.arrayInputLabel, children: label }), jsx("div", { children: jsx(AnimatePresence, { children: values.map((value, index) => (jsxs(motion.div, { className: `${styles$k.arrayInputItem} ${fields.length > 1 ? styles$k.complexItem : ''}`, style: itemStyle, initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0 }, transition: {
284
+ duration: 0.3,
285
+ ease: "easeInOut",
286
+ layout: { duration: 0.2 }
287
+ }, children: [jsx("div", { className: styles$k.fieldsWrapper, children: fields.map((field) => (jsx("div", { style: inputStyle, children: jsx(TextInput, { value: value[field.name] || '', onChange: (newValue) => handleChange(index, field.name, newValue), label: field.label, type: field.type, placeholder: field.placeholder }) }, field.name))) }), jsx(Button, { variant: "ghost", size: "small", onClick: () => handleRemove(index), "aria-label": "Remove item", className: styles$k.removeButton, children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) })] }, generateKey(value, index)))) }) }), jsxs(Button, { variant: "primary", size: "small", onClick: handleAdd, className: styles$k.addButton, children: ["Add ", label] })] }));
280
288
  }
281
289
 
282
290
  var styles$j = {"checkboxLabel":"Checkbox-module_checkboxLabel__4tBVg","checkbox":"Checkbox-module_checkbox__BbJul","checkboxText":"Checkbox-module_checkboxText__oJsc9"};
@@ -825,8 +833,15 @@ var styles$e = {"toggleContainer":"Toggle-module_toggleContainer__QxqQb","toggle
825
833
  * @returns {JSX.Element} The rendered Toggle component
826
834
  */
827
835
  function Toggle(props) {
828
- const { isOn, onToggle, leftLabel, rightLabel, leftIcon, rightIcon } = props;
829
- return (jsxs("div", { className: styles$e.toggleContainer, children: [jsxs("button", { className: `${styles$e.toggleButton} ${!isOn ? styles$e.active : ''}`, onClick: () => onToggle(false), children: [leftIcon, leftLabel] }), jsxs("button", { className: `${styles$e.toggleButton} ${isOn ? styles$e.active : ''}`, onClick: () => onToggle(true), children: [rightIcon, rightLabel] })] }));
836
+ const { isOn, onToggle, leftLabel, rightLabel, leftIcon, rightIcon, className, style } = props;
837
+ // Ensure content stays centered by merging styles
838
+ const buttonStyle = {
839
+ display: 'flex',
840
+ alignItems: 'center',
841
+ justifyContent: 'center',
842
+ ...style
843
+ };
844
+ return (jsxs("div", { className: `${styles$e.toggleContainer} ${className || ''}`, children: [jsxs("button", { className: `${styles$e.toggleButton} ${!isOn ? styles$e.active : ''}`, onClick: () => onToggle(false), style: buttonStyle, children: [leftIcon, leftLabel] }), jsxs("button", { className: `${styles$e.toggleButton} ${isOn ? styles$e.active : ''}`, onClick: () => onToggle(true), style: buttonStyle, children: [rightIcon, rightLabel] })] }));
830
845
  }
831
846
 
832
847
  var styles$d = {"container":"NumberStepper-module_container__WSGlU","header":"NumberStepper-module_header__qXI1Y","icon":"NumberStepper-module_icon__vHgsw","label":"NumberStepper-module_label__AYr3g","stepper":"NumberStepper-module_stepper__oQhTp","disabled":"NumberStepper-module_disabled__kGB-g","button":"NumberStepper-module_button__YcjRt","buttonIcon":"NumberStepper-module_buttonIcon__odXec","valueContainer":"NumberStepper-module_valueContainer__87w2D","valueWrapper":"NumberStepper-module_valueWrapper__TH65N","value":"NumberStepper-module_value__BxJeD","limits":"NumberStepper-module_limits__-UrRE","limit":"NumberStepper-module_limit__7nbIP","small":"NumberStepper-module_small__P-k96","large":"NumberStepper-module_large__Lz6lk","outlined":"NumberStepper-module_outlined__CIXv7","filled":"NumberStepper-module_filled__IxOg-","pulse":"NumberStepper-module_pulse__51oUo"};
@@ -1178,7 +1193,8 @@ const EditFAB = ({ canEdit, isEditMode, hasUnsavedChanges = false, isSaving = fa
1178
1193
 
1179
1194
  var styles$a = {"searchContainer":"SearchBar-module_searchContainer__TdM1w","searchInputWrapper":"SearchBar-module_searchInputWrapper__kCZLU","searchIcon":"SearchBar-module_searchIcon__IIxEu","searchInput":"SearchBar-module_searchInput__V4gkE","clearButton":"SearchBar-module_clearButton__7fNIY","filterSelect":"SearchBar-module_filterSelect__xIVE4","resultsDropdown":"SearchBar-module_resultsDropdown__yh6NF","loadingState":"SearchBar-module_loadingState__4gidK","emptyState":"SearchBar-module_emptyState__RbI4s","spinner":"SearchBar-module_spinner__PMc6-","resultsGroups":"SearchBar-module_resultsGroups__U24DC","resultGroup":"SearchBar-module_resultGroup__SoTQH","groupHeader":"SearchBar-module_groupHeader__bFRHA","groupIcon":"SearchBar-module_groupIcon__9ENM-","groupTitle":"SearchBar-module_groupTitle__ZekZs","groupCount":"SearchBar-module_groupCount__PQIqw","groupResults":"SearchBar-module_groupResults__xTF52","resultItem":"SearchBar-module_resultItem__VaKKy","highlighted":"SearchBar-module_highlighted__Q-3sH","resultTitle":"SearchBar-module_resultTitle__i1uqL","resultSubtitle":"SearchBar-module_resultSubtitle__LQOJ1","resultMeta":"SearchBar-module_resultMeta__Kmkrn","resultContent":"SearchBar-module_resultContent__TzVzL","highlight":"SearchBar-module_highlight__Q3PSP"};
1180
1195
 
1181
- const filterOptions = [
1196
+ // Default filter options for backwards compatibility
1197
+ const defaultFilterOptions = [
1182
1198
  { value: 'all', label: 'All', icon: FiSearch },
1183
1199
  { value: 'projects', label: 'Projects', icon: FiFolder },
1184
1200
  { value: 'clients', label: 'Clients', icon: FiUsers },
@@ -1186,16 +1202,18 @@ const filterOptions = [
1186
1202
  { value: 'interactions', label: 'Interactions', icon: FiMessageSquare },
1187
1203
  { value: 'team', label: 'Team', icon: FiUserPlus },
1188
1204
  ];
1189
- const entityIcons = {
1205
+ const defaultEntityIcons = {
1190
1206
  projects: FiFolder,
1191
1207
  clients: FiUsers,
1192
1208
  contacts: FiBook,
1193
1209
  interactions: FiMessageSquare,
1194
1210
  team: FiUserPlus,
1195
1211
  };
1196
- const SearchBar = ({ className, placeholder = "Search (Ctrl+Space)...", onSearch, onResultClick, onClear, debounceDelay = 300, minSearchLength = 2, showFilter = true, enableKeyboardShortcut = true }) => {
1212
+ const SearchBar = ({ className, placeholder = "Search (Ctrl+Space)...", onSearch, onResultClick, onClear, debounceDelay = 300, minSearchLength = 2, showFilter = true, enableKeyboardShortcut = true, filterOptions: customFilterOptions, entityIcons: customEntityIcons }) => {
1213
+ const filterOptions = customFilterOptions ?? defaultFilterOptions;
1214
+ const entityIcons = customEntityIcons ?? defaultEntityIcons;
1197
1215
  const [query, setQuery] = useState('');
1198
- const [filter, setFilter] = useState('all');
1216
+ const [filter, setFilter] = useState(filterOptions[0]?.value ?? 'all');
1199
1217
  const [results, setResults] = useState([]);
1200
1218
  const [isLoading, setIsLoading] = useState(false);
1201
1219
  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
@@ -1524,15 +1542,16 @@ function SiJira (props) {
1524
1542
 
1525
1543
  var styles$6 = {"tabs":"Tabs-module_tabs__Vlvn7","tab":"Tabs-module_tab__uQKim","tabIcon":"Tabs-module_tabIcon__AgN-O"};
1526
1544
 
1527
- const tabs = [
1545
+ // Default tabs for backwards compatibility
1546
+ const defaultTabs = [
1528
1547
  { id: 'details', icon: FiInfo, label: 'Dettagli' },
1529
1548
  { id: 'github', icon: FiGithub, label: 'GitHub' },
1530
1549
  { id: 'jira', icon: SiJira, label: 'Jira' },
1531
1550
  { id: 'functional', icon: FiInfo, label: 'Analisi funzionale' }
1532
1551
  ];
1533
- const Tabs = ({ activeTab, onTabChange }) => {
1534
- return (jsx("div", { className: styles$6.tabs, children: tabs.map((tab) => {
1535
- const Icon = tab.icon;
1552
+ const Tabs = ({ activeTab, onTabChange, tabs: customTabs, className = '' }) => {
1553
+ const tabs = customTabs ?? defaultTabs;
1554
+ return (jsx("div", { className: `${styles$6.tabs} ${className}`, children: tabs.map((tab) => {
1536
1555
  const isActive = activeTab === tab.id;
1537
1556
  return (jsxs(motion.button, { className: styles$6.tab, "data-active": isActive, onClick: () => onTabChange(tab.id), style: { position: 'relative' }, children: [jsx(motion.div, { animate: {
1538
1557
  rotate: isActive ? [0, -10, 10, -5, 5, 0] : 0,
@@ -1541,7 +1560,7 @@ const Tabs = ({ activeTab, onTabChange }) => {
1541
1560
  duration: 0.5,
1542
1561
  ease: 'easeInOut'
1543
1562
  }
1544
- }, children: jsx(Icon, { className: styles$6.tabIcon }) }), jsx("span", { children: tab.label })] }, tab.id));
1563
+ }, children: tab.icon && (typeof tab.icon === 'function' ? (jsx("span", { className: styles$6.tabIcon, children: React.createElement(tab.icon) })) : (jsx("span", { className: styles$6.tabIcon, children: tab.icon }))) }), jsx("span", { children: tab.label })] }, tab.id));
1545
1564
  }) }));
1546
1565
  };
1547
1566
 
@@ -2225,11 +2244,22 @@ const BooleansHeatmap = ({ data, habitName, width = 800, height = 200, habitColo
2225
2244
  var styles$1 = {"container":"SunburstChart-module_container__w1ZYc","title":"SunburstChart-module_title__T6Ak7","chart":"SunburstChart-module_chart__BFM6E","tooltip":"SunburstChart-module_tooltip__TuTAN"};
2226
2245
 
2227
2246
  const COLOR_PALETTE = [
2228
- '#d4af37', '#FFD700', '#FFA500', '#FF8C00',
2229
- '#FF6347', '#DC143C', '#8B4513', '#A0522D',
2230
- '#DEB887', '#F4A460', '#D2691E', '#CD853F'
2247
+ '#6366f1', '#8b5cf6', '#06b6d4', '#10b981',
2248
+ '#f59e0b', '#ef4444', '#ec4899', '#84cc16',
2249
+ '#f97316', '#3b82f6', '#14b8a6', '#f59e0b'
2231
2250
  ];
2232
- const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Chart', tagColors = {} }) => {
2251
+ // Calculate text color based on background luminance for optimal contrast
2252
+ const getTextColor$1 = (backgroundColor) => {
2253
+ const color = d3.color(backgroundColor);
2254
+ if (!color)
2255
+ return '#ffffff';
2256
+ const rgb = color.rgb();
2257
+ // Calculate relative luminance using WCAG formula
2258
+ const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
2259
+ // Return white text for dark backgrounds, black for light backgrounds
2260
+ return luminance > 0.5 ? '#000000' : '#ffffff';
2261
+ };
2262
+ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Chart', tagColors = {}, unit = 'items', centerLabel }) => {
2233
2263
  const svgRef = useRef(null);
2234
2264
  const colorMap = useRef(new Map()).current;
2235
2265
  const colorIndex = useRef(0);
@@ -2272,7 +2302,8 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
2272
2302
  .startAngle(d => d.x0)
2273
2303
  .endAngle(d => d.x1)
2274
2304
  .innerRadius(d => Math.sqrt(d.y0))
2275
- .outerRadius(d => Math.sqrt(d.y1));
2305
+ .outerRadius(d => Math.sqrt(d.y1))
2306
+ .cornerRadius(3);
2276
2307
  const tooltip = d3.select('body').append('div')
2277
2308
  .attr('class', styles$1.tooltip)
2278
2309
  .style('opacity', 0)
@@ -2291,11 +2322,20 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
2291
2322
  .attr('stroke', 'var(--bg-primary)')
2292
2323
  .attr('stroke-width', 2)
2293
2324
  .style('cursor', 'pointer')
2325
+ .style('filter', 'drop-shadow(0 1px 3px rgba(0,0,0,0.12))')
2294
2326
  .on('mouseover', function (event, d) {
2327
+ const hoverArc = d3.arc()
2328
+ .startAngle(d => d.x0)
2329
+ .endAngle(d => d.x1)
2330
+ .innerRadius(d => Math.sqrt(d.y0) - 2)
2331
+ .outerRadius(d => Math.sqrt(d.y1) + 4)
2332
+ .cornerRadius(3);
2295
2333
  d3.select(this)
2296
2334
  .transition()
2297
- .duration(200)
2298
- .style('opacity', 0.8);
2335
+ .duration(150)
2336
+ .attr('d', d => hoverArc(d))
2337
+ .style('filter', 'drop-shadow(0 2px 8px rgba(0,0,0,0.2))')
2338
+ .style('opacity', 0.9);
2299
2339
  tooltip.transition()
2300
2340
  .duration(200)
2301
2341
  .style('opacity', 1);
@@ -2309,10 +2349,12 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
2309
2349
  .style('left', (event.pageX + 10) + 'px')
2310
2350
  .style('top', (event.pageY - 28) + 'px');
2311
2351
  })
2312
- .on('mouseout', function () {
2352
+ .on('mouseout', function (event, d) {
2313
2353
  d3.select(this)
2314
2354
  .transition()
2315
- .duration(200)
2355
+ .duration(150)
2356
+ .attr('d', d => arc(d))
2357
+ .style('filter', 'drop-shadow(0 1px 3px rgba(0,0,0,0.12))')
2316
2358
  .style('opacity', 1);
2317
2359
  tooltip.transition()
2318
2360
  .duration(500)
@@ -2322,9 +2364,32 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
2322
2364
  const angle = d.x1 - d.x0;
2323
2365
  return angle > 0.15 && d.depth <= 2;
2324
2366
  };
2325
- g.selectAll('text')
2367
+ // Calculate average background color for center text contrast
2368
+ const allSegments = nodes.filter(d => d.depth === 1);
2369
+ const avgColor = allSegments.length > 0 ? d3.interpolateRgb.gamma(2.2)(...allSegments.map(d => getColor(d.data.name, 1)))(0.5) : '#ffffff';
2370
+ const centerTextColor = getTextColor$1(avgColor);
2371
+ // Add center text
2372
+ g.append('text')
2373
+ .attr('text-anchor', 'middle')
2374
+ .attr('alignment-baseline', 'middle')
2375
+ .attr('font-size', '18px')
2376
+ .attr('font-weight', 'bold')
2377
+ .attr('fill', centerTextColor)
2378
+ .style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 3px rgba(0,0,0,0.5)' : '0 1px 3px rgba(255,255,255,0.5)')
2379
+ .text(centerLabel || data.name || 'Total');
2380
+ g.append('text')
2381
+ .attr('text-anchor', 'middle')
2382
+ .attr('alignment-baseline', 'middle')
2383
+ .attr('y', 20)
2384
+ .attr('font-size', '14px')
2385
+ .attr('font-weight', '500')
2386
+ .attr('fill', centerTextColor)
2387
+ .style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 2px rgba(0,0,0,0.4)' : '0 1px 2px rgba(255,255,255,0.4)')
2388
+ .text(`${(root.value || 0).toLocaleString()} ${unit}`);
2389
+ g.selectAll('text.segment-label')
2326
2390
  .data(nodes.filter(d => d.depth > 0 && d.value && d.value > 0 && shouldDisplayLabel(d)))
2327
2391
  .enter().append('text')
2392
+ .attr('class', 'segment-label')
2328
2393
  .attr('transform', d => {
2329
2394
  const angle = (d.x0 + d.x1) / 2;
2330
2395
  const radius = (Math.sqrt(d.y0) + Math.sqrt(d.y1)) / 2;
@@ -2334,11 +2399,32 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
2334
2399
  })
2335
2400
  .attr('text-anchor', 'middle')
2336
2401
  .attr('alignment-baseline', 'middle')
2337
- .attr('font-size', '12px')
2338
- .attr('fill', 'var(--text-inverse)')
2339
- .attr('font-weight', 'var(--font-medium)')
2402
+ .attr('font-size', d => d.depth === 1 ? '13px' : '11px')
2403
+ .attr('fill', d => {
2404
+ let ancestor = d;
2405
+ while (ancestor.depth > 1 && ancestor.parent) {
2406
+ ancestor = ancestor.parent;
2407
+ }
2408
+ const segmentColor = getColor(ancestor.data.name, d.depth);
2409
+ return getTextColor$1(segmentColor);
2410
+ })
2411
+ .attr('font-weight', '600')
2340
2412
  .style('pointer-events', 'none')
2341
- .text(d => d.data.name.substring(0, 10));
2413
+ .style('text-shadow', d => {
2414
+ let ancestor = d;
2415
+ while (ancestor.depth > 1 && ancestor.parent) {
2416
+ ancestor = ancestor.parent;
2417
+ }
2418
+ const segmentColor = getColor(ancestor.data.name, d.depth);
2419
+ const textColor = getTextColor$1(segmentColor);
2420
+ // Use contrasting shadow color
2421
+ const shadowColor = textColor === '#ffffff' ? 'rgba(0,0,0,0.5)' : 'rgba(255,255,255,0.5)';
2422
+ return `0 1px 2px ${shadowColor}`;
2423
+ })
2424
+ .text(d => {
2425
+ const maxLength = d.depth === 1 ? 12 : 8;
2426
+ return d.data.name.substring(0, maxLength);
2427
+ });
2342
2428
  return () => {
2343
2429
  tooltip.remove();
2344
2430
  };
@@ -2349,12 +2435,23 @@ const SunburstChart = ({ data, width = 500, height = 500, title = 'Sunburst Char
2349
2435
  var styles = {"container":"PieChart-module_container__tXjbe","title":"PieChart-module_title__61o0R","chartContainer":"PieChart-module_chartContainer__uLmOz","chart":"PieChart-module_chart__3nqON","legend":"PieChart-module_legend__rAWgh","legendItem":"PieChart-module_legendItem__Nb031","legendColor":"PieChart-module_legendColor__fLuv9","legendLabel":"PieChart-module_legendLabel__xbjBr","legendValue":"PieChart-module_legendValue__h2WS2","tooltip":"PieChart-module_tooltip__140RU"};
2350
2436
 
2351
2437
  const DEFAULT_COLORS = [
2352
- '#d4af37', '#FFD700', '#FFA500', '#FF8C00',
2353
- '#FF6347', '#DC143C', '#8B4513', '#A0522D',
2354
- '#DEB887', '#F4A460', '#D2691E', '#CD853F',
2355
- '#B8860B', '#DAA520', '#F0E68C', '#BDB76B'
2438
+ '#6366f1', '#8b5cf6', '#06b6d4', '#10b981',
2439
+ '#f59e0b', '#ef4444', '#ec4899', '#84cc16',
2440
+ '#f97316', '#3b82f6', '#8b5cf6', '#14b8a6',
2441
+ '#f59e0b', '#ef4444', '#06b6d4', '#10b981'
2356
2442
  ];
2357
- const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', showLegend = true }) => {
2443
+ // Calculate text color based on background luminance for optimal contrast
2444
+ const getTextColor = (backgroundColor) => {
2445
+ const color = d3.color(backgroundColor);
2446
+ if (!color)
2447
+ return '#ffffff';
2448
+ const rgb = color.rgb();
2449
+ // Calculate relative luminance using WCAG formula
2450
+ const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
2451
+ // Return white text for dark backgrounds, black for light backgrounds
2452
+ return luminance > 0.5 ? '#000000' : '#ffffff';
2453
+ };
2454
+ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', showLegend = true, unit = 'items', centerLabel }) => {
2358
2455
  const svgRef = useRef(null);
2359
2456
  const radius = Math.min(width, height) / 2 - 20;
2360
2457
  useEffect(() => {
@@ -2368,8 +2465,9 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
2368
2465
  .value(d => d.value)
2369
2466
  .sort(null);
2370
2467
  const arc = d3.arc()
2371
- .innerRadius(0)
2372
- .outerRadius(radius);
2468
+ .innerRadius(radius * 0.4)
2469
+ .outerRadius(radius)
2470
+ .cornerRadius(4);
2373
2471
  const labelArc = d3.arc()
2374
2472
  .innerRadius(radius * 0.7)
2375
2473
  .outerRadius(radius * 0.7);
@@ -2387,13 +2485,19 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
2387
2485
  .attr('d', d => arc(d))
2388
2486
  .attr('fill', (d, i) => d.data.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length])
2389
2487
  .attr('stroke', 'var(--bg-primary)')
2390
- .attr('stroke-width', 2)
2488
+ .attr('stroke-width', 3)
2391
2489
  .style('cursor', 'pointer')
2490
+ .style('filter', 'drop-shadow(0 2px 8px rgba(0,0,0,0.15))')
2392
2491
  .on('mouseover', function (event, d) {
2492
+ const hoverArc = d3.arc()
2493
+ .innerRadius(radius * 0.4)
2494
+ .outerRadius(radius * 1.05)
2495
+ .cornerRadius(4);
2393
2496
  d3.select(this)
2394
2497
  .transition()
2395
2498
  .duration(200)
2396
- .style('opacity', 0.8);
2499
+ .attr('d', d => hoverArc(d))
2500
+ .style('filter', 'drop-shadow(0 4px 12px rgba(0,0,0,0.25))');
2397
2501
  tooltip.transition()
2398
2502
  .duration(200)
2399
2503
  .style('opacity', 1);
@@ -2406,27 +2510,59 @@ const PieChart = ({ data, width = 400, height = 400, title = 'Distribution', sho
2406
2510
  .style('left', (event.pageX + 10) + 'px')
2407
2511
  .style('top', (event.pageY - 28) + 'px');
2408
2512
  })
2409
- .on('mouseout', function () {
2513
+ .on('mouseout', function (event, d) {
2410
2514
  d3.select(this)
2411
2515
  .transition()
2412
2516
  .duration(200)
2413
- .style('opacity', 1);
2517
+ .attr('d', d => arc(d))
2518
+ .style('filter', 'drop-shadow(0 2px 8px rgba(0,0,0,0.15))');
2414
2519
  tooltip.transition()
2415
2520
  .duration(500)
2416
2521
  .style('opacity', 0);
2417
2522
  });
2418
- arcs.filter(d => (d.endAngle - d.startAngle) > 0.3)
2523
+ // Calculate average background color for center text contrast
2524
+ const avgColor = data.length > 0 ? d3.interpolateRgb.gamma(2.2)(...data.map((d, i) => d.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length]))(0.5) : '#ffffff';
2525
+ const centerTextColor = getTextColor(avgColor);
2526
+ // Add center text for donut
2527
+ g.append('text')
2528
+ .attr('text-anchor', 'middle')
2529
+ .attr('alignment-baseline', 'middle')
2530
+ .attr('font-size', '20px')
2531
+ .attr('font-weight', 'bold')
2532
+ .attr('fill', centerTextColor)
2533
+ .style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 3px rgba(0,0,0,0.5)' : '0 1px 3px rgba(255,255,255,0.5)')
2534
+ .text(centerLabel || 'Total');
2535
+ g.append('text')
2536
+ .attr('text-anchor', 'middle')
2537
+ .attr('alignment-baseline', 'middle')
2538
+ .attr('y', 22)
2539
+ .attr('font-size', '16px')
2540
+ .attr('font-weight', '600')
2541
+ .attr('fill', centerTextColor)
2542
+ .style('text-shadow', centerTextColor === '#ffffff' ? '0 1px 2px rgba(0,0,0,0.4)' : '0 1px 2px rgba(255,255,255,0.4)')
2543
+ .text(`${total.toLocaleString()} ${unit}`);
2544
+ arcs.filter(d => (d.endAngle - d.startAngle) > 0.2)
2419
2545
  .append('text')
2420
2546
  .attr('transform', d => `translate(${labelArc.centroid(d)})`)
2421
2547
  .attr('text-anchor', 'middle')
2422
2548
  .attr('alignment-baseline', 'middle')
2423
- .attr('font-size', '12px')
2424
- .attr('fill', 'var(--text-inverse)')
2425
- .attr('font-weight', 'var(--font-semibold)')
2549
+ .attr('font-size', '13px')
2550
+ .attr('fill', (d, i) => {
2551
+ const segmentColor = d.data.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length];
2552
+ return getTextColor(segmentColor);
2553
+ })
2554
+ .attr('font-weight', '600')
2426
2555
  .style('pointer-events', 'none')
2556
+ .style('text-shadow', (d, i) => {
2557
+ const segmentColor = d.data.color || DEFAULT_COLORS[i % DEFAULT_COLORS.length];
2558
+ const textColor = getTextColor(segmentColor);
2559
+ // Use contrasting shadow color
2560
+ const shadowColor = textColor === '#ffffff' ? 'rgba(0,0,0,0.4)' : 'rgba(255,255,255,0.4)';
2561
+ return `0 1px 2px ${shadowColor}`;
2562
+ })
2427
2563
  .text(d => {
2428
2564
  const percentage = ((d.data.value / total) * 100);
2429
- return percentage > 5 ? `${percentage.toFixed(1)}%` : '';
2565
+ return percentage > 8 ? `${percentage.toFixed(0)}%` : '';
2430
2566
  });
2431
2567
  return () => {
2432
2568
  tooltip.remove();