web-mojo 2.3.0 → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/dist/admin-models.cjs.js +1 -1
  3. package/dist/admin-models.es.js +1 -1
  4. package/dist/admin.cjs.js +1 -1
  5. package/dist/admin.es.js +1 -1
  6. package/dist/auth.cjs.js +1 -1
  7. package/dist/auth.es.js +1 -1
  8. package/dist/charts.cjs.js +1 -1
  9. package/dist/charts.es.js +1 -1
  10. package/dist/chunks/{AssistantPanelView-DCEV6VeI.js → AssistantPanelView-72i9d6rq.js} +2 -2
  11. package/dist/chunks/{AssistantPanelView-DCEV6VeI.js.map → AssistantPanelView-72i9d6rq.js.map} +1 -1
  12. package/dist/chunks/{AssistantPanelView-BG34Qbfj.js → AssistantPanelView-D-0f5hZS.js} +2 -2
  13. package/dist/chunks/{AssistantPanelView-BG34Qbfj.js.map → AssistantPanelView-D-0f5hZS.js.map} +1 -1
  14. package/dist/chunks/{ChatView-B73uox2v.js → ChatView-CXykdAV1.js} +2 -2
  15. package/dist/chunks/{ChatView-B73uox2v.js.map → ChatView-CXykdAV1.js.map} +1 -1
  16. package/dist/chunks/{ChatView-W8daOwIo.js → ChatView-ys5MIiBf.js} +2 -2
  17. package/dist/chunks/{ChatView-W8daOwIo.js.map → ChatView-ys5MIiBf.js.map} +1 -1
  18. package/dist/chunks/{Collection-BZlmtcuL.js → Collection-BpUmNuDZ.js} +2 -2
  19. package/dist/chunks/{Collection-BZlmtcuL.js.map → Collection-BpUmNuDZ.js.map} +1 -1
  20. package/dist/chunks/{Collection-Bwoq6muu.js → Collection-CY6BblFn.js} +2 -2
  21. package/dist/chunks/{Collection-Bwoq6muu.js.map → Collection-CY6BblFn.js.map} +1 -1
  22. package/dist/chunks/{ContextMenu-q76hjQb6.js → ContextMenu-PtN50qH2.js} +2 -2
  23. package/dist/chunks/{ContextMenu-q76hjQb6.js.map → ContextMenu-PtN50qH2.js.map} +1 -1
  24. package/dist/chunks/{ContextMenu-BPPtuqKk.js → ContextMenu-XQVFU0mL.js} +2 -2
  25. package/dist/chunks/{ContextMenu-BPPtuqKk.js.map → ContextMenu-XQVFU0mL.js.map} +1 -1
  26. package/dist/chunks/{DataView-k-7wmk5_.js → DataView-BTi_BZHx.js} +2 -2
  27. package/dist/chunks/{DataView-k-7wmk5_.js.map → DataView-BTi_BZHx.js.map} +1 -1
  28. package/dist/chunks/{DataView-BbrwHMV4.js → DataView-WHRh1o6E.js} +2 -2
  29. package/dist/chunks/{DataView-BbrwHMV4.js.map → DataView-WHRh1o6E.js.map} +1 -1
  30. package/dist/chunks/{FormView-Dcy7XOtC.js → FormView-BzaGMf5_.js} +3 -3
  31. package/dist/chunks/{FormView-Dcy7XOtC.js.map → FormView-BzaGMf5_.js.map} +1 -1
  32. package/dist/chunks/{FormView-DPSuwWMq.js → FormView-DTD-Zy22.js} +3 -3
  33. package/dist/chunks/{FormView-DPSuwWMq.js.map → FormView-DTD-Zy22.js.map} +1 -1
  34. package/dist/chunks/{ListView-iGBsD4a7.js → ListView-BsnnTcmC.js} +2 -2
  35. package/dist/chunks/{ListView-iGBsD4a7.js.map → ListView-BsnnTcmC.js.map} +1 -1
  36. package/dist/chunks/{ListView-DHC-yBIw.js → ListView-Xf7kO6Me.js} +2 -2
  37. package/dist/chunks/{ListView-DHC-yBIw.js.map → ListView-Xf7kO6Me.js.map} +1 -1
  38. package/dist/chunks/{MetricsCountryMapView-CAD9wR_T.js → MetricsCountryMapView-BzGOi1d2.js} +2 -2
  39. package/dist/chunks/{MetricsCountryMapView-CAD9wR_T.js.map → MetricsCountryMapView-BzGOi1d2.js.map} +1 -1
  40. package/dist/chunks/{MetricsCountryMapView-Dzk3Yrzx.js → MetricsCountryMapView-C-S00Wiw.js} +2 -2
  41. package/dist/chunks/{MetricsCountryMapView-Dzk3Yrzx.js.map → MetricsCountryMapView-C-S00Wiw.js.map} +1 -1
  42. package/dist/chunks/{Modal-DuULCMFZ.js → Modal-GWjyfcz5.js} +3 -3
  43. package/dist/chunks/Modal-GWjyfcz5.js.map +1 -0
  44. package/dist/chunks/{Modal-DBJU16cc.js → Modal-wrfWfQhv.js} +3 -3
  45. package/dist/chunks/Modal-wrfWfQhv.js.map +1 -0
  46. package/dist/chunks/{Passkeys-CGRZ8ZMv.js → Passkeys-BviQX3_5.js} +2 -2
  47. package/dist/chunks/{Passkeys-CGRZ8ZMv.js.map → Passkeys-BviQX3_5.js.map} +1 -1
  48. package/dist/chunks/{Passkeys-Dr8-oSm9.js → Passkeys-gXR1Rc6C.js} +2 -2
  49. package/dist/chunks/{Passkeys-Dr8-oSm9.js.map → Passkeys-gXR1Rc6C.js.map} +1 -1
  50. package/dist/chunks/TokenManager-C6aXkRaI.js +2 -0
  51. package/dist/chunks/TokenManager-C6aXkRaI.js.map +1 -0
  52. package/dist/chunks/TokenManager-DgvhhTqN.js +2 -0
  53. package/dist/chunks/TokenManager-DgvhhTqN.js.map +1 -0
  54. package/dist/chunks/{User-Dg7xpYEI.js → User-B_Urf7U7.js} +2 -2
  55. package/dist/chunks/{User-Dg7xpYEI.js.map → User-B_Urf7U7.js.map} +1 -1
  56. package/dist/chunks/{User-DNQhdBtI.js → User-KTBU_5cr.js} +2 -2
  57. package/dist/chunks/{User-DNQhdBtI.js.map → User-KTBU_5cr.js.map} +1 -1
  58. package/dist/chunks/{UserProfileView-Bpz3VZmP.js → UserProfileView-BmduMJ86.js} +2 -2
  59. package/dist/chunks/{UserProfileView-Bpz3VZmP.js.map → UserProfileView-BmduMJ86.js.map} +1 -1
  60. package/dist/chunks/{UserProfileView-B5nczdfw.js → UserProfileView-COxSyPB0.js} +2 -2
  61. package/dist/chunks/{UserProfileView-B5nczdfw.js.map → UserProfileView-COxSyPB0.js.map} +1 -1
  62. package/dist/chunks/{View-Yazho7OL.js → View-C8UWvaSM.js} +2 -2
  63. package/dist/chunks/{View-Yazho7OL.js.map → View-C8UWvaSM.js.map} +1 -1
  64. package/dist/chunks/{View-C5n3sIFi.js → View-Cvs2TY7b.js} +2 -2
  65. package/dist/chunks/{View-C5n3sIFi.js.map → View-Cvs2TY7b.js.map} +1 -1
  66. package/dist/chunks/{WebApp-CeiDNV6L.js → WebApp-DuwanN2O.js} +2 -2
  67. package/dist/chunks/{WebApp-CeiDNV6L.js.map → WebApp-DuwanN2O.js.map} +1 -1
  68. package/dist/chunks/{WebApp-irKlhuFX.js → WebApp-kbRq7dM_.js} +2 -2
  69. package/dist/chunks/{WebApp-irKlhuFX.js.map → WebApp-kbRq7dM_.js.map} +1 -1
  70. package/dist/chunks/{admin-CGoTpXfs.js → admin-BcJ_hgzn.js} +2 -2
  71. package/dist/chunks/{admin-CGoTpXfs.js.map → admin-BcJ_hgzn.js.map} +1 -1
  72. package/dist/chunks/{admin-B5tf0zOO.js → admin-DtjMWe6R.js} +2 -2
  73. package/dist/chunks/{admin-B5tf0zOO.js.map → admin-DtjMWe6R.js.map} +1 -1
  74. package/dist/chunks/{exportChart-kQ-we4Cp.js → exportChart-Bkxr7mCe.js} +2 -2
  75. package/dist/chunks/{exportChart-kQ-we4Cp.js.map → exportChart-Bkxr7mCe.js.map} +1 -1
  76. package/dist/chunks/{exportChart-BTJBYkOz.js → exportChart-Dn2pioNl.js} +2 -2
  77. package/dist/chunks/{exportChart-BTJBYkOz.js.map → exportChart-Dn2pioNl.js.map} +1 -1
  78. package/dist/chunks/{index-BNjCQA7q.js → index-BCWkcyOy.js} +2 -2
  79. package/dist/chunks/{index-BNjCQA7q.js.map → index-BCWkcyOy.js.map} +1 -1
  80. package/dist/chunks/{index-DBsIDOAa.js → index-CJeTVskY.js} +2 -2
  81. package/dist/chunks/{index-DBsIDOAa.js.map → index-CJeTVskY.js.map} +1 -1
  82. package/dist/chunks/{version-CYGIXntv.js → version-CB0Ssm9c.js} +2 -2
  83. package/dist/chunks/{version-CYGIXntv.js.map → version-CB0Ssm9c.js.map} +1 -1
  84. package/dist/chunks/{version-BURwX10Q.js → version-DkxW4rIi.js} +2 -2
  85. package/dist/chunks/{version-BURwX10Q.js.map → version-DkxW4rIi.js.map} +1 -1
  86. package/dist/core.css +134 -109
  87. package/dist/css/web-mojo.css +1 -1
  88. package/dist/docit.cjs.js +1 -1
  89. package/dist/docit.es.js +1 -1
  90. package/dist/index.cjs.js +1 -1
  91. package/dist/index.cjs.js.map +1 -1
  92. package/dist/index.es.js +1 -1
  93. package/dist/index.es.js.map +1 -1
  94. package/dist/lightbox.cjs.js +1 -1
  95. package/dist/lightbox.es.js +1 -1
  96. package/dist/map.cjs.js +1 -1
  97. package/dist/map.es.js +1 -1
  98. package/dist/portal.css +32 -0
  99. package/dist/timeline.cjs.js +1 -1
  100. package/dist/timeline.es.js +1 -1
  101. package/dist/user-profile.cjs.js +1 -1
  102. package/dist/user-profile.es.js +1 -1
  103. package/dist/web-mojo.lite.iife.js +33 -9
  104. package/dist/web-mojo.lite.iife.js.map +1 -1
  105. package/dist/web-mojo.lite.iife.min.js +5 -5
  106. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  107. package/package.json +1 -1
  108. package/dist/chunks/Modal-DBJU16cc.js.map +0 -1
  109. package/dist/chunks/Modal-DuULCMFZ.js.map +0 -1
  110. package/dist/chunks/TokenManager-CcQFvaFD.js +0 -2
  111. package/dist/chunks/TokenManager-CcQFvaFD.js.map +0 -1
  112. package/dist/chunks/TokenManager-DEWZqbuo.js +0 -2
  113. package/dist/chunks/TokenManager-DEWZqbuo.js.map +0 -1
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./UserProfileView-Bpz3VZmP.js"),t=require("./View-Yazho7OL.js"),i=require("./Passkeys-Dr8-oSm9.js");class ActivityRow extends i.TableRow{get logMessage(){const e=this.model?.get("log");if(!e)return"";if("string"==typeof e)try{const t=JSON.parse(e);return t.message||t.type||e.substring(0,120)}catch{return e.length>120?e.substring(0,120)+"…":e}return"object"==typeof e?e.message||e.type||JSON.stringify(e).substring(0,120):String(e)}get levelText(){return this.model?.get("level")||"log"}get levelBadgeClass(){const e=this.model?.get("level");return"error"===e?"bg-danger":"warn"===e?"bg-warning text-dark":"info"===e?"bg-info":"bg-secondary"}get methodPath(){const e=this.model?.get("method")||"",t=this.model?.get("path")||"";return e||t?`${e} ${t}`.trim():""}}class ProfileActivitySection extends t.View{constructor(e={}){super({className:"profile-activity-section",template:'<div id="activity-table"></div>',...e})}async onInit(){await super.onInit(),this.tableView=new i.TableView({containerId:"activity-table",collection:new i.LogList({size:10}),defaultQuery:{uid:this.model.id,sort:"-created"},hideActivePillNames:["uid","sort"],itemClass:ActivityRow,columns:[{key:"level",label:"Level",sortable:!0,template:'<span class="badge {{levelBadgeClass}}">{{levelText}}</span>',filter:{type:"select",options:["info","warn","error"]}},{key:"log",label:"Message",template:"{{logMessage}}"},{key:"kind",label:"Kind",sortable:!0,visibility:"md"},{key:"path",label:"Path",visibility:"lg",template:"{{methodPath}}"},{key:"ip",label:"IP",visibility:"xl"},{key:"created|relative",label:"Time",sortable:!0}],searchable:!0,sortable:!0,filterable:!0,paginated:!0,showAdd:!1,showExport:!1,tableOptions:{striped:!1,hover:!0,size:"sm"},emptyMessage:"No activity logs available"}),this.addChild(this.tableView)}}exports.PasskeySetupView=e.PasskeySetupView,exports.ProfileApiKeysSection=e.ProfileApiKeysSection,exports.ProfileConnectedSection=e.ProfileConnectedSection,exports.ProfileDevicesSection=e.ProfileDevicesSection,exports.ProfileGroupsSection=e.ProfileGroupsSection,exports.ProfileNotificationsSection=e.ProfileNotificationsSection,exports.ProfileOverviewSection=e.ProfileOverviewSection,exports.ProfilePermissionsSection=e.ProfilePermissionsSection,exports.ProfilePersonalSection=e.ProfilePersonalSection,exports.ProfileSecurityEventsSection=e.ProfileSecurityEventsSection,exports.ProfileSecuritySection=e.ProfileSecuritySection,exports.ProfileSessionsSection=e.ProfileSessionsSection,exports.UserProfileView=e.UserProfileView,exports.ProfileActivitySection=ProfileActivitySection;
2
- //# sourceMappingURL=index-BNjCQA7q.js.map
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./UserProfileView-BmduMJ86.js"),t=require("./View-C8UWvaSM.js"),i=require("./Passkeys-gXR1Rc6C.js");class ActivityRow extends i.TableRow{get logMessage(){const e=this.model?.get("log");if(!e)return"";if("string"==typeof e)try{const t=JSON.parse(e);return t.message||t.type||e.substring(0,120)}catch{return e.length>120?e.substring(0,120)+"…":e}return"object"==typeof e?e.message||e.type||JSON.stringify(e).substring(0,120):String(e)}get levelText(){return this.model?.get("level")||"log"}get levelBadgeClass(){const e=this.model?.get("level");return"error"===e?"bg-danger":"warn"===e?"bg-warning text-dark":"info"===e?"bg-info":"bg-secondary"}get methodPath(){const e=this.model?.get("method")||"",t=this.model?.get("path")||"";return e||t?`${e} ${t}`.trim():""}}class ProfileActivitySection extends t.View{constructor(e={}){super({className:"profile-activity-section",template:'<div id="activity-table"></div>',...e})}async onInit(){await super.onInit(),this.tableView=new i.TableView({containerId:"activity-table",collection:new i.LogList({size:10}),defaultQuery:{uid:this.model.id,sort:"-created"},hideActivePillNames:["uid","sort"],itemClass:ActivityRow,columns:[{key:"level",label:"Level",sortable:!0,template:'<span class="badge {{levelBadgeClass}}">{{levelText}}</span>',filter:{type:"select",options:["info","warn","error"]}},{key:"log",label:"Message",template:"{{logMessage}}"},{key:"kind",label:"Kind",sortable:!0,visibility:"md"},{key:"path",label:"Path",visibility:"lg",template:"{{methodPath}}"},{key:"ip",label:"IP",visibility:"xl"},{key:"created|relative",label:"Time",sortable:!0}],searchable:!0,sortable:!0,filterable:!0,paginated:!0,showAdd:!1,showExport:!1,tableOptions:{striped:!1,hover:!0,size:"sm"},emptyMessage:"No activity logs available"}),this.addChild(this.tableView)}}exports.PasskeySetupView=e.PasskeySetupView,exports.ProfileApiKeysSection=e.ProfileApiKeysSection,exports.ProfileConnectedSection=e.ProfileConnectedSection,exports.ProfileDevicesSection=e.ProfileDevicesSection,exports.ProfileGroupsSection=e.ProfileGroupsSection,exports.ProfileNotificationsSection=e.ProfileNotificationsSection,exports.ProfileOverviewSection=e.ProfileOverviewSection,exports.ProfilePermissionsSection=e.ProfilePermissionsSection,exports.ProfilePersonalSection=e.ProfilePersonalSection,exports.ProfileSecurityEventsSection=e.ProfileSecurityEventsSection,exports.ProfileSecuritySection=e.ProfileSecuritySection,exports.ProfileSessionsSection=e.ProfileSessionsSection,exports.UserProfileView=e.UserProfileView,exports.ProfileActivitySection=ProfileActivitySection;
2
+ //# sourceMappingURL=index-BCWkcyOy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-BNjCQA7q.js","sources":["../../src/extensions/user-profile/views/ProfileActivitySection.js"],"sourcesContent":["/**\n * ProfileActivitySection - Activity log tab\n *\n * Uses TableView + LogList to show user activity\n * with parsed log messages, level badges, kind, path, and time.\n * Includes pagination, search, and level filtering.\n */\nimport View from '@core/View.js';\nimport TableView from '@core/views/table/TableView.js';\nimport TableRow from '@core/views/table/TableRow.js';\nimport { LogList } from '@core/models/Log.js';\n\nclass ActivityRow extends TableRow {\n get logMessage() {\n const log = this.model?.get('log');\n if (!log) return '';\n if (typeof log === 'string') {\n try {\n const parsed = JSON.parse(log);\n return parsed.message || parsed.type || log.substring(0, 120);\n } catch {\n return log.length > 120 ? log.substring(0, 120) + '…' : log;\n }\n }\n if (typeof log === 'object') {\n return log.message || log.type || JSON.stringify(log).substring(0, 120);\n }\n return String(log);\n }\n\n get levelText() {\n return this.model?.get('level') || 'log';\n }\n\n get levelBadgeClass() {\n const level = this.model?.get('level');\n if (level === 'error') return 'bg-danger';\n if (level === 'warn') return 'bg-warning text-dark';\n if (level === 'info') return 'bg-info';\n return 'bg-secondary';\n }\n\n get methodPath() {\n const method = this.model?.get('method') || '';\n const path = this.model?.get('path') || '';\n if (!method && !path) return '';\n return `${method} ${path}`.trim();\n }\n}\n\nexport default class ProfileActivitySection extends View {\n constructor(options = {}) {\n super({\n className: 'profile-activity-section',\n template: `<div id=\"activity-table\"></div>`,\n ...options\n });\n }\n\n async onInit() {\n await super.onInit();\n this.tableView = new TableView({\n containerId: 'activity-table',\n collection: new LogList({ size: 10 }),\n defaultQuery: { uid: this.model.id, sort: '-created' },\n hideActivePillNames: ['uid', 'sort'],\n itemClass: ActivityRow,\n columns: [\n {\n key: 'level',\n label: 'Level',\n sortable: true,\n template: '<span class=\"badge {{levelBadgeClass}}\">{{levelText}}</span>',\n filter: { type: 'select', options: ['info', 'warn', 'error'] }\n },\n {\n key: 'log',\n label: 'Message',\n template: '{{logMessage}}'\n },\n { key: 'kind', label: 'Kind', sortable: true, visibility: 'md' },\n {\n key: 'path',\n label: 'Path',\n visibility: 'lg',\n template: '{{methodPath}}'\n },\n { key: 'ip', label: 'IP', visibility: 'xl' },\n { key: 'created|relative', label: 'Time', sortable: true }\n ],\n searchable: true,\n sortable: true,\n filterable: true,\n paginated: true,\n showAdd: false,\n showExport: false,\n tableOptions: {\n striped: false,\n hover: true,\n size: 'sm'\n },\n emptyMessage: 'No activity logs available'\n });\n this.addChild(this.tableView);\n }\n}\n"],"names":["ActivityRow","TableRow","logMessage","log","this","model","get","parsed","JSON","parse","message","type","substring","length","stringify","String","levelText","levelBadgeClass","level","methodPath","method","path","trim","ProfileActivitySection","View","constructor","options","super","className","template","onInit","tableView","TableView","containerId","collection","LogList","size","defaultQuery","uid","id","sort","hideActivePillNames","itemClass","columns","key","label","sortable","filter","visibility","searchable","filterable","paginated","showAdd","showExport","tableOptions","striped","hover","emptyMessage","addChild"],"mappings":"qMAYA,MAAMA,oBAAoBC,EAAAA,SACtB,cAAIC,GACA,MAAMC,EAAMC,KAAKC,OAAOC,IAAI,OAC5B,IAAKH,EAAK,MAAO,GACjB,GAAmB,iBAARA,EACP,IACI,MAAMI,EAASC,KAAKC,MAAMN,GAC1B,OAAOI,EAAOG,SAAWH,EAAOI,MAAQR,EAAIS,UAAU,EAAG,IAC7D,CAAA,MACI,OAAOT,EAAIU,OAAS,IAAMV,EAAIS,UAAU,EAAG,KAAO,IAAMT,CAC5D,CAEJ,MAAmB,iBAARA,EACAA,EAAIO,SAAWP,EAAIQ,MAAQH,KAAKM,UAAUX,GAAKS,UAAU,EAAG,KAEhEG,OAAOZ,EAClB,CAEA,aAAIa,GACA,OAAOZ,KAAKC,OAAOC,IAAI,UAAY,KACvC,CAEA,mBAAIW,GACA,MAAMC,EAAQd,KAAKC,OAAOC,IAAI,SAC9B,MAAc,UAAVY,EAA0B,YAChB,SAAVA,EAAyB,uBACf,SAAVA,EAAyB,UACtB,cACX,CAEA,cAAIC,GACA,MAAMC,EAAShB,KAAKC,OAAOC,IAAI,WAAa,GACtCe,EAAOjB,KAAKC,OAAOC,IAAI,SAAW,GACxC,OAAKc,GAAWC,EACT,GAAGD,KAAUC,IAAOC,OADE,EAEjC,EAGW,MAAMC,+BAA+BC,EAAAA,KAChD,WAAAC,CAAYC,EAAU,IAClBC,MAAM,CACFC,UAAW,2BACXC,SAAU,qCACPH,GAEX,CAEA,YAAMI,SACIH,MAAMG,SACZ1B,KAAK2B,UAAY,IAAIC,YAAU,CAC3BC,YAAa,iBACbC,WAAY,IAAIC,EAAAA,QAAQ,CAAEC,KAAM,KAChCC,aAAc,CAAEC,IAAKlC,KAAKC,MAAMkC,GAAIC,KAAM,YAC1CC,oBAAqB,CAAC,MAAO,QAC7BC,UAAW1C,YACX2C,QAAS,CACL,CACIC,IAAK,QACLC,MAAO,QACPC,UAAU,EACVjB,SAAU,+DACVkB,OAAQ,CAAEpC,KAAM,SAAUe,QAAS,CAAC,OAAQ,OAAQ,WAExD,CACIkB,IAAK,MACLC,MAAO,UACPhB,SAAU,kBAEd,CAAEe,IAAK,OAAQC,MAAO,OAAQC,UAAU,EAAME,WAAY,MAC1D,CACIJ,IAAK,OACLC,MAAO,OACPG,WAAY,KACZnB,SAAU,kBAEd,CAAEe,IAAK,KAAMC,MAAO,KAAMG,WAAY,MACtC,CAAEJ,IAAK,mBAAoBC,MAAO,OAAQC,UAAU,IAExDG,YAAY,EACZH,UAAU,EACVI,YAAY,EACZC,WAAW,EACXC,SAAS,EACTC,YAAY,EACZC,aAAc,CACVC,SAAS,EACTC,OAAO,EACPpB,KAAM,MAEVqB,aAAc,+BAElBrD,KAAKsD,SAAStD,KAAK2B,UACvB"}
1
+ {"version":3,"file":"index-BCWkcyOy.js","sources":["../../src/extensions/user-profile/views/ProfileActivitySection.js"],"sourcesContent":["/**\n * ProfileActivitySection - Activity log tab\n *\n * Uses TableView + LogList to show user activity\n * with parsed log messages, level badges, kind, path, and time.\n * Includes pagination, search, and level filtering.\n */\nimport View from '@core/View.js';\nimport TableView from '@core/views/table/TableView.js';\nimport TableRow from '@core/views/table/TableRow.js';\nimport { LogList } from '@core/models/Log.js';\n\nclass ActivityRow extends TableRow {\n get logMessage() {\n const log = this.model?.get('log');\n if (!log) return '';\n if (typeof log === 'string') {\n try {\n const parsed = JSON.parse(log);\n return parsed.message || parsed.type || log.substring(0, 120);\n } catch {\n return log.length > 120 ? log.substring(0, 120) + '…' : log;\n }\n }\n if (typeof log === 'object') {\n return log.message || log.type || JSON.stringify(log).substring(0, 120);\n }\n return String(log);\n }\n\n get levelText() {\n return this.model?.get('level') || 'log';\n }\n\n get levelBadgeClass() {\n const level = this.model?.get('level');\n if (level === 'error') return 'bg-danger';\n if (level === 'warn') return 'bg-warning text-dark';\n if (level === 'info') return 'bg-info';\n return 'bg-secondary';\n }\n\n get methodPath() {\n const method = this.model?.get('method') || '';\n const path = this.model?.get('path') || '';\n if (!method && !path) return '';\n return `${method} ${path}`.trim();\n }\n}\n\nexport default class ProfileActivitySection extends View {\n constructor(options = {}) {\n super({\n className: 'profile-activity-section',\n template: `<div id=\"activity-table\"></div>`,\n ...options\n });\n }\n\n async onInit() {\n await super.onInit();\n this.tableView = new TableView({\n containerId: 'activity-table',\n collection: new LogList({ size: 10 }),\n defaultQuery: { uid: this.model.id, sort: '-created' },\n hideActivePillNames: ['uid', 'sort'],\n itemClass: ActivityRow,\n columns: [\n {\n key: 'level',\n label: 'Level',\n sortable: true,\n template: '<span class=\"badge {{levelBadgeClass}}\">{{levelText}}</span>',\n filter: { type: 'select', options: ['info', 'warn', 'error'] }\n },\n {\n key: 'log',\n label: 'Message',\n template: '{{logMessage}}'\n },\n { key: 'kind', label: 'Kind', sortable: true, visibility: 'md' },\n {\n key: 'path',\n label: 'Path',\n visibility: 'lg',\n template: '{{methodPath}}'\n },\n { key: 'ip', label: 'IP', visibility: 'xl' },\n { key: 'created|relative', label: 'Time', sortable: true }\n ],\n searchable: true,\n sortable: true,\n filterable: true,\n paginated: true,\n showAdd: false,\n showExport: false,\n tableOptions: {\n striped: false,\n hover: true,\n size: 'sm'\n },\n emptyMessage: 'No activity logs available'\n });\n this.addChild(this.tableView);\n }\n}\n"],"names":["ActivityRow","TableRow","logMessage","log","this","model","get","parsed","JSON","parse","message","type","substring","length","stringify","String","levelText","levelBadgeClass","level","methodPath","method","path","trim","ProfileActivitySection","View","constructor","options","super","className","template","onInit","tableView","TableView","containerId","collection","LogList","size","defaultQuery","uid","id","sort","hideActivePillNames","itemClass","columns","key","label","sortable","filter","visibility","searchable","filterable","paginated","showAdd","showExport","tableOptions","striped","hover","emptyMessage","addChild"],"mappings":"qMAYA,MAAMA,oBAAoBC,EAAAA,SACtB,cAAIC,GACA,MAAMC,EAAMC,KAAKC,OAAOC,IAAI,OAC5B,IAAKH,EAAK,MAAO,GACjB,GAAmB,iBAARA,EACP,IACI,MAAMI,EAASC,KAAKC,MAAMN,GAC1B,OAAOI,EAAOG,SAAWH,EAAOI,MAAQR,EAAIS,UAAU,EAAG,IAC7D,CAAA,MACI,OAAOT,EAAIU,OAAS,IAAMV,EAAIS,UAAU,EAAG,KAAO,IAAMT,CAC5D,CAEJ,MAAmB,iBAARA,EACAA,EAAIO,SAAWP,EAAIQ,MAAQH,KAAKM,UAAUX,GAAKS,UAAU,EAAG,KAEhEG,OAAOZ,EAClB,CAEA,aAAIa,GACA,OAAOZ,KAAKC,OAAOC,IAAI,UAAY,KACvC,CAEA,mBAAIW,GACA,MAAMC,EAAQd,KAAKC,OAAOC,IAAI,SAC9B,MAAc,UAAVY,EAA0B,YAChB,SAAVA,EAAyB,uBACf,SAAVA,EAAyB,UACtB,cACX,CAEA,cAAIC,GACA,MAAMC,EAAShB,KAAKC,OAAOC,IAAI,WAAa,GACtCe,EAAOjB,KAAKC,OAAOC,IAAI,SAAW,GACxC,OAAKc,GAAWC,EACT,GAAGD,KAAUC,IAAOC,OADE,EAEjC,EAGW,MAAMC,+BAA+BC,EAAAA,KAChD,WAAAC,CAAYC,EAAU,IAClBC,MAAM,CACFC,UAAW,2BACXC,SAAU,qCACPH,GAEX,CAEA,YAAMI,SACIH,MAAMG,SACZ1B,KAAK2B,UAAY,IAAIC,YAAU,CAC3BC,YAAa,iBACbC,WAAY,IAAIC,EAAAA,QAAQ,CAAEC,KAAM,KAChCC,aAAc,CAAEC,IAAKlC,KAAKC,MAAMkC,GAAIC,KAAM,YAC1CC,oBAAqB,CAAC,MAAO,QAC7BC,UAAW1C,YACX2C,QAAS,CACL,CACIC,IAAK,QACLC,MAAO,QACPC,UAAU,EACVjB,SAAU,+DACVkB,OAAQ,CAAEpC,KAAM,SAAUe,QAAS,CAAC,OAAQ,OAAQ,WAExD,CACIkB,IAAK,MACLC,MAAO,UACPhB,SAAU,kBAEd,CAAEe,IAAK,OAAQC,MAAO,OAAQC,UAAU,EAAME,WAAY,MAC1D,CACIJ,IAAK,OACLC,MAAO,OACPG,WAAY,KACZnB,SAAU,kBAEd,CAAEe,IAAK,KAAMC,MAAO,KAAMG,WAAY,MACtC,CAAEJ,IAAK,mBAAoBC,MAAO,OAAQC,UAAU,IAExDG,YAAY,EACZH,UAAU,EACVI,YAAY,EACZC,WAAW,EACXC,SAAS,EACTC,YAAY,EACZC,aAAc,CACVC,SAAS,EACTC,OAAO,EACPpB,KAAM,MAEVqB,aAAc,+BAElBrD,KAAKsD,SAAStD,KAAK2B,UACvB"}
@@ -1,2 +1,2 @@
1
- import{U as e,P as t}from"./UserProfileView-B5nczdfw.js";import{a as i,b as s,c as o,d as l,e as a,f as r,g as n,h as c,i as d,j as g,k as f}from"./UserProfileView-B5nczdfw.js";import{V as m}from"./View-C5n3sIFi.js";import{T as y,f as p,c as b}from"./Passkeys-CGRZ8ZMv.js";class ActivityRow extends b{get logMessage(){const e=this.model?.get("log");if(!e)return"";if("string"==typeof e)try{const t=JSON.parse(e);return t.message||t.type||e.substring(0,120)}catch{return e.length>120?e.substring(0,120)+"…":e}return"object"==typeof e?e.message||e.type||JSON.stringify(e).substring(0,120):String(e)}get levelText(){return this.model?.get("level")||"log"}get levelBadgeClass(){const e=this.model?.get("level");return"error"===e?"bg-danger":"warn"===e?"bg-warning text-dark":"info"===e?"bg-info":"bg-secondary"}get methodPath(){const e=this.model?.get("method")||"",t=this.model?.get("path")||"";return e||t?`${e} ${t}`.trim():""}}class ProfileActivitySection extends m{constructor(e={}){super({className:"profile-activity-section",template:'<div id="activity-table"></div>',...e})}async onInit(){await super.onInit(),this.tableView=new y({containerId:"activity-table",collection:new p({size:10}),defaultQuery:{uid:this.model.id,sort:"-created"},hideActivePillNames:["uid","sort"],itemClass:ActivityRow,columns:[{key:"level",label:"Level",sortable:!0,template:'<span class="badge {{levelBadgeClass}}">{{levelText}}</span>',filter:{type:"select",options:["info","warn","error"]}},{key:"log",label:"Message",template:"{{logMessage}}"},{key:"kind",label:"Kind",sortable:!0,visibility:"md"},{key:"path",label:"Path",visibility:"lg",template:"{{methodPath}}"},{key:"ip",label:"IP",visibility:"xl"},{key:"created|relative",label:"Time",sortable:!0}],searchable:!0,sortable:!0,filterable:!0,paginated:!0,showAdd:!1,showExport:!1,tableOptions:{striped:!1,hover:!0,size:"sm"},emptyMessage:"No activity logs available"}),this.addChild(this.tableView)}}export{t as PasskeySetupView,ProfileActivitySection,i as ProfileApiKeysSection,s as ProfileConnectedSection,o as ProfileDevicesSection,l as ProfileGroupsSection,a as ProfileNotificationsSection,r as ProfileOverviewSection,n as ProfilePermissionsSection,c as ProfilePersonalSection,d as ProfileSecurityEventsSection,g as ProfileSecuritySection,f as ProfileSessionsSection,e as UserProfileView};
2
- //# sourceMappingURL=index-DBsIDOAa.js.map
1
+ import{U as e,P as t}from"./UserProfileView-COxSyPB0.js";import{a as i,b as s,c as o,d as l,e as a,f as r,g as n,h as c,i as d,j as g,k as f}from"./UserProfileView-COxSyPB0.js";import{V as m}from"./View-Cvs2TY7b.js";import{T as y,f as p,c as b}from"./Passkeys-BviQX3_5.js";class ActivityRow extends b{get logMessage(){const e=this.model?.get("log");if(!e)return"";if("string"==typeof e)try{const t=JSON.parse(e);return t.message||t.type||e.substring(0,120)}catch{return e.length>120?e.substring(0,120)+"…":e}return"object"==typeof e?e.message||e.type||JSON.stringify(e).substring(0,120):String(e)}get levelText(){return this.model?.get("level")||"log"}get levelBadgeClass(){const e=this.model?.get("level");return"error"===e?"bg-danger":"warn"===e?"bg-warning text-dark":"info"===e?"bg-info":"bg-secondary"}get methodPath(){const e=this.model?.get("method")||"",t=this.model?.get("path")||"";return e||t?`${e} ${t}`.trim():""}}class ProfileActivitySection extends m{constructor(e={}){super({className:"profile-activity-section",template:'<div id="activity-table"></div>',...e})}async onInit(){await super.onInit(),this.tableView=new y({containerId:"activity-table",collection:new p({size:10}),defaultQuery:{uid:this.model.id,sort:"-created"},hideActivePillNames:["uid","sort"],itemClass:ActivityRow,columns:[{key:"level",label:"Level",sortable:!0,template:'<span class="badge {{levelBadgeClass}}">{{levelText}}</span>',filter:{type:"select",options:["info","warn","error"]}},{key:"log",label:"Message",template:"{{logMessage}}"},{key:"kind",label:"Kind",sortable:!0,visibility:"md"},{key:"path",label:"Path",visibility:"lg",template:"{{methodPath}}"},{key:"ip",label:"IP",visibility:"xl"},{key:"created|relative",label:"Time",sortable:!0}],searchable:!0,sortable:!0,filterable:!0,paginated:!0,showAdd:!1,showExport:!1,tableOptions:{striped:!1,hover:!0,size:"sm"},emptyMessage:"No activity logs available"}),this.addChild(this.tableView)}}export{t as PasskeySetupView,ProfileActivitySection,i as ProfileApiKeysSection,s as ProfileConnectedSection,o as ProfileDevicesSection,l as ProfileGroupsSection,a as ProfileNotificationsSection,r as ProfileOverviewSection,n as ProfilePermissionsSection,c as ProfilePersonalSection,d as ProfileSecurityEventsSection,g as ProfileSecuritySection,f as ProfileSessionsSection,e as UserProfileView};
2
+ //# sourceMappingURL=index-CJeTVskY.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-DBsIDOAa.js","sources":["../../src/extensions/user-profile/views/ProfileActivitySection.js"],"sourcesContent":["/**\n * ProfileActivitySection - Activity log tab\n *\n * Uses TableView + LogList to show user activity\n * with parsed log messages, level badges, kind, path, and time.\n * Includes pagination, search, and level filtering.\n */\nimport View from '@core/View.js';\nimport TableView from '@core/views/table/TableView.js';\nimport TableRow from '@core/views/table/TableRow.js';\nimport { LogList } from '@core/models/Log.js';\n\nclass ActivityRow extends TableRow {\n get logMessage() {\n const log = this.model?.get('log');\n if (!log) return '';\n if (typeof log === 'string') {\n try {\n const parsed = JSON.parse(log);\n return parsed.message || parsed.type || log.substring(0, 120);\n } catch {\n return log.length > 120 ? log.substring(0, 120) + '…' : log;\n }\n }\n if (typeof log === 'object') {\n return log.message || log.type || JSON.stringify(log).substring(0, 120);\n }\n return String(log);\n }\n\n get levelText() {\n return this.model?.get('level') || 'log';\n }\n\n get levelBadgeClass() {\n const level = this.model?.get('level');\n if (level === 'error') return 'bg-danger';\n if (level === 'warn') return 'bg-warning text-dark';\n if (level === 'info') return 'bg-info';\n return 'bg-secondary';\n }\n\n get methodPath() {\n const method = this.model?.get('method') || '';\n const path = this.model?.get('path') || '';\n if (!method && !path) return '';\n return `${method} ${path}`.trim();\n }\n}\n\nexport default class ProfileActivitySection extends View {\n constructor(options = {}) {\n super({\n className: 'profile-activity-section',\n template: `<div id=\"activity-table\"></div>`,\n ...options\n });\n }\n\n async onInit() {\n await super.onInit();\n this.tableView = new TableView({\n containerId: 'activity-table',\n collection: new LogList({ size: 10 }),\n defaultQuery: { uid: this.model.id, sort: '-created' },\n hideActivePillNames: ['uid', 'sort'],\n itemClass: ActivityRow,\n columns: [\n {\n key: 'level',\n label: 'Level',\n sortable: true,\n template: '<span class=\"badge {{levelBadgeClass}}\">{{levelText}}</span>',\n filter: { type: 'select', options: ['info', 'warn', 'error'] }\n },\n {\n key: 'log',\n label: 'Message',\n template: '{{logMessage}}'\n },\n { key: 'kind', label: 'Kind', sortable: true, visibility: 'md' },\n {\n key: 'path',\n label: 'Path',\n visibility: 'lg',\n template: '{{methodPath}}'\n },\n { key: 'ip', label: 'IP', visibility: 'xl' },\n { key: 'created|relative', label: 'Time', sortable: true }\n ],\n searchable: true,\n sortable: true,\n filterable: true,\n paginated: true,\n showAdd: false,\n showExport: false,\n tableOptions: {\n striped: false,\n hover: true,\n size: 'sm'\n },\n emptyMessage: 'No activity logs available'\n });\n this.addChild(this.tableView);\n }\n}\n"],"names":["ActivityRow","TableRow","logMessage","log","this","model","get","parsed","JSON","parse","message","type","substring","length","stringify","String","levelText","levelBadgeClass","level","methodPath","method","path","trim","ProfileActivitySection","View","constructor","options","super","className","template","onInit","tableView","TableView","containerId","collection","LogList","size","defaultQuery","uid","id","sort","hideActivePillNames","itemClass","columns","key","label","sortable","filter","visibility","searchable","filterable","paginated","showAdd","showExport","tableOptions","striped","hover","emptyMessage","addChild"],"mappings":"iRAYA,MAAMA,oBAAoBC,EACtB,cAAIC,GACA,MAAMC,EAAMC,KAAKC,OAAOC,IAAI,OAC5B,IAAKH,EAAK,MAAO,GACjB,GAAmB,iBAARA,EACP,IACI,MAAMI,EAASC,KAAKC,MAAMN,GAC1B,OAAOI,EAAOG,SAAWH,EAAOI,MAAQR,EAAIS,UAAU,EAAG,IAC7D,CAAA,MACI,OAAOT,EAAIU,OAAS,IAAMV,EAAIS,UAAU,EAAG,KAAO,IAAMT,CAC5D,CAEJ,MAAmB,iBAARA,EACAA,EAAIO,SAAWP,EAAIQ,MAAQH,KAAKM,UAAUX,GAAKS,UAAU,EAAG,KAEhEG,OAAOZ,EAClB,CAEA,aAAIa,GACA,OAAOZ,KAAKC,OAAOC,IAAI,UAAY,KACvC,CAEA,mBAAIW,GACA,MAAMC,EAAQd,KAAKC,OAAOC,IAAI,SAC9B,MAAc,UAAVY,EAA0B,YAChB,SAAVA,EAAyB,uBACf,SAAVA,EAAyB,UACtB,cACX,CAEA,cAAIC,GACA,MAAMC,EAAShB,KAAKC,OAAOC,IAAI,WAAa,GACtCe,EAAOjB,KAAKC,OAAOC,IAAI,SAAW,GACxC,OAAKc,GAAWC,EACT,GAAGD,KAAUC,IAAOC,OADE,EAEjC,EAGW,MAAMC,+BAA+BC,EAChD,WAAAC,CAAYC,EAAU,IAClBC,MAAM,CACFC,UAAW,2BACXC,SAAU,qCACPH,GAEX,CAEA,YAAMI,SACIH,MAAMG,SACZ1B,KAAK2B,UAAY,IAAIC,EAAU,CAC3BC,YAAa,iBACbC,WAAY,IAAIC,EAAQ,CAAEC,KAAM,KAChCC,aAAc,CAAEC,IAAKlC,KAAKC,MAAMkC,GAAIC,KAAM,YAC1CC,oBAAqB,CAAC,MAAO,QAC7BC,UAAW1C,YACX2C,QAAS,CACL,CACIC,IAAK,QACLC,MAAO,QACPC,UAAU,EACVjB,SAAU,+DACVkB,OAAQ,CAAEpC,KAAM,SAAUe,QAAS,CAAC,OAAQ,OAAQ,WAExD,CACIkB,IAAK,MACLC,MAAO,UACPhB,SAAU,kBAEd,CAAEe,IAAK,OAAQC,MAAO,OAAQC,UAAU,EAAME,WAAY,MAC1D,CACIJ,IAAK,OACLC,MAAO,OACPG,WAAY,KACZnB,SAAU,kBAEd,CAAEe,IAAK,KAAMC,MAAO,KAAMG,WAAY,MACtC,CAAEJ,IAAK,mBAAoBC,MAAO,OAAQC,UAAU,IAExDG,YAAY,EACZH,UAAU,EACVI,YAAY,EACZC,WAAW,EACXC,SAAS,EACTC,YAAY,EACZC,aAAc,CACVC,SAAS,EACTC,OAAO,EACPpB,KAAM,MAEVqB,aAAc,+BAElBrD,KAAKsD,SAAStD,KAAK2B,UACvB"}
1
+ {"version":3,"file":"index-CJeTVskY.js","sources":["../../src/extensions/user-profile/views/ProfileActivitySection.js"],"sourcesContent":["/**\n * ProfileActivitySection - Activity log tab\n *\n * Uses TableView + LogList to show user activity\n * with parsed log messages, level badges, kind, path, and time.\n * Includes pagination, search, and level filtering.\n */\nimport View from '@core/View.js';\nimport TableView from '@core/views/table/TableView.js';\nimport TableRow from '@core/views/table/TableRow.js';\nimport { LogList } from '@core/models/Log.js';\n\nclass ActivityRow extends TableRow {\n get logMessage() {\n const log = this.model?.get('log');\n if (!log) return '';\n if (typeof log === 'string') {\n try {\n const parsed = JSON.parse(log);\n return parsed.message || parsed.type || log.substring(0, 120);\n } catch {\n return log.length > 120 ? log.substring(0, 120) + '…' : log;\n }\n }\n if (typeof log === 'object') {\n return log.message || log.type || JSON.stringify(log).substring(0, 120);\n }\n return String(log);\n }\n\n get levelText() {\n return this.model?.get('level') || 'log';\n }\n\n get levelBadgeClass() {\n const level = this.model?.get('level');\n if (level === 'error') return 'bg-danger';\n if (level === 'warn') return 'bg-warning text-dark';\n if (level === 'info') return 'bg-info';\n return 'bg-secondary';\n }\n\n get methodPath() {\n const method = this.model?.get('method') || '';\n const path = this.model?.get('path') || '';\n if (!method && !path) return '';\n return `${method} ${path}`.trim();\n }\n}\n\nexport default class ProfileActivitySection extends View {\n constructor(options = {}) {\n super({\n className: 'profile-activity-section',\n template: `<div id=\"activity-table\"></div>`,\n ...options\n });\n }\n\n async onInit() {\n await super.onInit();\n this.tableView = new TableView({\n containerId: 'activity-table',\n collection: new LogList({ size: 10 }),\n defaultQuery: { uid: this.model.id, sort: '-created' },\n hideActivePillNames: ['uid', 'sort'],\n itemClass: ActivityRow,\n columns: [\n {\n key: 'level',\n label: 'Level',\n sortable: true,\n template: '<span class=\"badge {{levelBadgeClass}}\">{{levelText}}</span>',\n filter: { type: 'select', options: ['info', 'warn', 'error'] }\n },\n {\n key: 'log',\n label: 'Message',\n template: '{{logMessage}}'\n },\n { key: 'kind', label: 'Kind', sortable: true, visibility: 'md' },\n {\n key: 'path',\n label: 'Path',\n visibility: 'lg',\n template: '{{methodPath}}'\n },\n { key: 'ip', label: 'IP', visibility: 'xl' },\n { key: 'created|relative', label: 'Time', sortable: true }\n ],\n searchable: true,\n sortable: true,\n filterable: true,\n paginated: true,\n showAdd: false,\n showExport: false,\n tableOptions: {\n striped: false,\n hover: true,\n size: 'sm'\n },\n emptyMessage: 'No activity logs available'\n });\n this.addChild(this.tableView);\n }\n}\n"],"names":["ActivityRow","TableRow","logMessage","log","this","model","get","parsed","JSON","parse","message","type","substring","length","stringify","String","levelText","levelBadgeClass","level","methodPath","method","path","trim","ProfileActivitySection","View","constructor","options","super","className","template","onInit","tableView","TableView","containerId","collection","LogList","size","defaultQuery","uid","id","sort","hideActivePillNames","itemClass","columns","key","label","sortable","filter","visibility","searchable","filterable","paginated","showAdd","showExport","tableOptions","striped","hover","emptyMessage","addChild"],"mappings":"iRAYA,MAAMA,oBAAoBC,EACtB,cAAIC,GACA,MAAMC,EAAMC,KAAKC,OAAOC,IAAI,OAC5B,IAAKH,EAAK,MAAO,GACjB,GAAmB,iBAARA,EACP,IACI,MAAMI,EAASC,KAAKC,MAAMN,GAC1B,OAAOI,EAAOG,SAAWH,EAAOI,MAAQR,EAAIS,UAAU,EAAG,IAC7D,CAAA,MACI,OAAOT,EAAIU,OAAS,IAAMV,EAAIS,UAAU,EAAG,KAAO,IAAMT,CAC5D,CAEJ,MAAmB,iBAARA,EACAA,EAAIO,SAAWP,EAAIQ,MAAQH,KAAKM,UAAUX,GAAKS,UAAU,EAAG,KAEhEG,OAAOZ,EAClB,CAEA,aAAIa,GACA,OAAOZ,KAAKC,OAAOC,IAAI,UAAY,KACvC,CAEA,mBAAIW,GACA,MAAMC,EAAQd,KAAKC,OAAOC,IAAI,SAC9B,MAAc,UAAVY,EAA0B,YAChB,SAAVA,EAAyB,uBACf,SAAVA,EAAyB,UACtB,cACX,CAEA,cAAIC,GACA,MAAMC,EAAShB,KAAKC,OAAOC,IAAI,WAAa,GACtCe,EAAOjB,KAAKC,OAAOC,IAAI,SAAW,GACxC,OAAKc,GAAWC,EACT,GAAGD,KAAUC,IAAOC,OADE,EAEjC,EAGW,MAAMC,+BAA+BC,EAChD,WAAAC,CAAYC,EAAU,IAClBC,MAAM,CACFC,UAAW,2BACXC,SAAU,qCACPH,GAEX,CAEA,YAAMI,SACIH,MAAMG,SACZ1B,KAAK2B,UAAY,IAAIC,EAAU,CAC3BC,YAAa,iBACbC,WAAY,IAAIC,EAAQ,CAAEC,KAAM,KAChCC,aAAc,CAAEC,IAAKlC,KAAKC,MAAMkC,GAAIC,KAAM,YAC1CC,oBAAqB,CAAC,MAAO,QAC7BC,UAAW1C,YACX2C,QAAS,CACL,CACIC,IAAK,QACLC,MAAO,QACPC,UAAU,EACVjB,SAAU,+DACVkB,OAAQ,CAAEpC,KAAM,SAAUe,QAAS,CAAC,OAAQ,OAAQ,WAExD,CACIkB,IAAK,MACLC,MAAO,UACPhB,SAAU,kBAEd,CAAEe,IAAK,OAAQC,MAAO,OAAQC,UAAU,EAAME,WAAY,MAC1D,CACIJ,IAAK,OACLC,MAAO,OACPG,WAAY,KACZnB,SAAU,kBAEd,CAAEe,IAAK,KAAMC,MAAO,KAAMG,WAAY,MACtC,CAAEJ,IAAK,mBAAoBC,MAAO,OAAQC,UAAU,IAExDG,YAAY,EACZH,UAAU,EACVI,YAAY,EACZC,WAAW,EACXC,SAAS,EACTC,YAAY,EACZC,aAAc,CACVC,SAAS,EACTC,OAAO,EACPpB,KAAM,MAEVqB,aAAc,+BAElBrD,KAAKsD,SAAStD,KAAK2B,UACvB"}
@@ -1,2 +1,2 @@
1
- const i="2.3.0",n=2,o=3,s=0,O="2026-04-27T15:20:31.669Z",r={full:i,major:2,minor:3,revision:0,buildTime:O,toString(){return this.full},compare(i){const n=i=>i.split(".").map(Number),[o,s,O]=n(this.full),[r,w,e]=n(i);return o!==r?o-r:s!==w?s-w:O-e}};"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.VERSION=i,window.MOJO.VERSION_INFO=r,window.MOJO.version=i);export{O as B,i as V,r as a,n as b,o as c,s as d};
2
- //# sourceMappingURL=version-CYGIXntv.js.map
1
+ const i="2.3.2",n=2,o=3,s=2,O="2026-05-01T18:05:48.004Z",r={full:i,major:2,minor:3,revision:2,buildTime:O,toString(){return this.full},compare(i){const n=i=>i.split(".").map(Number),[o,s,O]=n(this.full),[r,w,e]=n(i);return o!==r?o-r:s!==w?s-w:O-e}};"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.VERSION=i,window.MOJO.VERSION_INFO=r,window.MOJO.version=i);export{O as B,i as V,r as a,n as b,o as c,s as d};
2
+ //# sourceMappingURL=version-CB0Ssm9c.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version-CYGIXntv.js","sources":["../../src/version.js"],"sourcesContent":["/**\n * MOJO Framework Version Information\n * Auto-generated on 2026-04-27T15:20:31.669Z\n */\n\nexport const VERSION = '2.3.0';\nexport const VERSION_MAJOR = 2;\nexport const VERSION_MINOR = 3;\nexport const VERSION_REVISION = 0;\nexport const BUILD_TIME = '2026-04-27T15:20:31.669Z';\n\n// Version object for easy access\nexport const VERSION_INFO = {\n full: VERSION,\n major: VERSION_MAJOR,\n minor: VERSION_MINOR,\n revision: VERSION_REVISION,\n buildTime: BUILD_TIME,\n toString() {\n return this.full;\n },\n compare(other) {\n const parseVer = (v) => v.split('.').map(Number);\n const [a1, a2, a3] = parseVer(this.full);\n const [b1, b2, b3] = parseVer(other);\n\n if (a1 !== b1) return a1 - b1;\n if (a2 !== b2) return a2 - b2;\n return a3 - b3;\n }\n};\n\n// Make version globally available if in browser\nif (typeof window !== 'undefined') {\n window.MOJO = window.MOJO || {};\n window.MOJO.VERSION = VERSION;\n window.MOJO.VERSION_INFO = VERSION_INFO;\n\n // Also add to MOJO.version for convenience\n window.MOJO.version = VERSION;\n}\n\nexport default VERSION_INFO;\n"],"names":["VERSION","VERSION_MAJOR","VERSION_MINOR","VERSION_REVISION","BUILD_TIME","VERSION_INFO","full","major","minor","revision","buildTime","toString","this","compare","other","parseVer","v","split","map","Number","a1","a2","a3","b1","b2","b3","window","MOJO","version"],"mappings":"AAKY,MAACA,EAAU,QACVC,EAAgB,EAChBC,EAAgB,EAChBC,EAAmB,EACnBC,EAAa,2BAGbC,EAAe,CACxBC,KAAMN,EACNO,MARyB,EASzBC,MARyB,EASzBC,SAR4B,EAS5BC,UAAWN,EACX,QAAAO,GACI,OAAOC,KAAKN,IAChB,EACA,OAAAO,CAAQC,GACJ,MAAMC,EAAYC,GAAMA,EAAEC,MAAM,KAAKC,IAAIC,SAClCC,EAAIC,EAAIC,GAAMP,EAASH,KAAKN,OAC5BiB,EAAIC,EAAIC,GAAMV,EAASD,GAE9B,OAAIM,IAAOG,EAAWH,EAAKG,EACvBF,IAAOG,EAAWH,EAAKG,EACpBF,EAAKG,CAChB,GAIkB,oBAAXC,SACPA,OAAOC,KAAOD,OAAOC,MAAQ,CAAA,EAC7BD,OAAOC,KAAK3B,QAAUA,EACtB0B,OAAOC,KAAKtB,aAAeA,EAG3BqB,OAAOC,KAAKC,QAAU5B"}
1
+ {"version":3,"file":"version-CB0Ssm9c.js","sources":["../../src/version.js"],"sourcesContent":["/**\n * MOJO Framework Version Information\n * Auto-generated on 2026-05-01T18:05:48.004Z\n */\n\nexport const VERSION = '2.3.2';\nexport const VERSION_MAJOR = 2;\nexport const VERSION_MINOR = 3;\nexport const VERSION_REVISION = 2;\nexport const BUILD_TIME = '2026-05-01T18:05:48.004Z';\n\n// Version object for easy access\nexport const VERSION_INFO = {\n full: VERSION,\n major: VERSION_MAJOR,\n minor: VERSION_MINOR,\n revision: VERSION_REVISION,\n buildTime: BUILD_TIME,\n toString() {\n return this.full;\n },\n compare(other) {\n const parseVer = (v) => v.split('.').map(Number);\n const [a1, a2, a3] = parseVer(this.full);\n const [b1, b2, b3] = parseVer(other);\n\n if (a1 !== b1) return a1 - b1;\n if (a2 !== b2) return a2 - b2;\n return a3 - b3;\n }\n};\n\n// Make version globally available if in browser\nif (typeof window !== 'undefined') {\n window.MOJO = window.MOJO || {};\n window.MOJO.VERSION = VERSION;\n window.MOJO.VERSION_INFO = VERSION_INFO;\n\n // Also add to MOJO.version for convenience\n window.MOJO.version = VERSION;\n}\n\nexport default VERSION_INFO;\n"],"names":["VERSION","VERSION_MAJOR","VERSION_MINOR","VERSION_REVISION","BUILD_TIME","VERSION_INFO","full","major","minor","revision","buildTime","toString","this","compare","other","parseVer","v","split","map","Number","a1","a2","a3","b1","b2","b3","window","MOJO","version"],"mappings":"AAKY,MAACA,EAAU,QACVC,EAAgB,EAChBC,EAAgB,EAChBC,EAAmB,EACnBC,EAAa,2BAGbC,EAAe,CACxBC,KAAMN,EACNO,MARyB,EASzBC,MARyB,EASzBC,SAR4B,EAS5BC,UAAWN,EACX,QAAAO,GACI,OAAOC,KAAKN,IAChB,EACA,OAAAO,CAAQC,GACJ,MAAMC,EAAYC,GAAMA,EAAEC,MAAM,KAAKC,IAAIC,SAClCC,EAAIC,EAAIC,GAAMP,EAASH,KAAKN,OAC5BiB,EAAIC,EAAIC,GAAMV,EAASD,GAE9B,OAAIM,IAAOG,EAAWH,EAAKG,EACvBF,IAAOG,EAAWH,EAAKG,EACpBF,EAAKG,CAChB,GAIkB,oBAAXC,SACPA,OAAOC,KAAOD,OAAOC,MAAQ,CAAA,EAC7BD,OAAOC,KAAK3B,QAAUA,EACtB0B,OAAOC,KAAKtB,aAAeA,EAG3BqB,OAAOC,KAAKC,QAAU5B"}
@@ -1,2 +1,2 @@
1
- "use strict";const O="2.3.0",o="2026-04-27T15:20:31.669Z",i={full:O,major:2,minor:3,revision:0,buildTime:o,toString(){return this.full},compare(O){const o=O=>O.split(".").map(Number),[i,r,t]=o(this.full),[e,n,s]=o(O);return i!==e?i-e:r!==n?r-n:t-s}};"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.VERSION=O,window.MOJO.VERSION_INFO=i,window.MOJO.version=O),exports.BUILD_TIME=o,exports.VERSION=O,exports.VERSION_INFO=i,exports.VERSION_MAJOR=2,exports.VERSION_MINOR=3,exports.VERSION_REVISION=0;
2
- //# sourceMappingURL=version-BURwX10Q.js.map
1
+ "use strict";const O="2.3.2",o="2026-05-01T18:05:48.004Z",i={full:O,major:2,minor:3,revision:2,buildTime:o,toString(){return this.full},compare(O){const o=O=>O.split(".").map(Number),[i,r,t]=o(this.full),[e,n,s]=o(O);return i!==e?i-e:r!==n?r-n:t-s}};"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.VERSION=O,window.MOJO.VERSION_INFO=i,window.MOJO.version=O),exports.BUILD_TIME=o,exports.VERSION=O,exports.VERSION_INFO=i,exports.VERSION_MAJOR=2,exports.VERSION_MINOR=3,exports.VERSION_REVISION=2;
2
+ //# sourceMappingURL=version-DkxW4rIi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version-BURwX10Q.js","sources":["../../src/version.js"],"sourcesContent":["/**\n * MOJO Framework Version Information\n * Auto-generated on 2026-04-27T15:20:31.669Z\n */\n\nexport const VERSION = '2.3.0';\nexport const VERSION_MAJOR = 2;\nexport const VERSION_MINOR = 3;\nexport const VERSION_REVISION = 0;\nexport const BUILD_TIME = '2026-04-27T15:20:31.669Z';\n\n// Version object for easy access\nexport const VERSION_INFO = {\n full: VERSION,\n major: VERSION_MAJOR,\n minor: VERSION_MINOR,\n revision: VERSION_REVISION,\n buildTime: BUILD_TIME,\n toString() {\n return this.full;\n },\n compare(other) {\n const parseVer = (v) => v.split('.').map(Number);\n const [a1, a2, a3] = parseVer(this.full);\n const [b1, b2, b3] = parseVer(other);\n\n if (a1 !== b1) return a1 - b1;\n if (a2 !== b2) return a2 - b2;\n return a3 - b3;\n }\n};\n\n// Make version globally available if in browser\nif (typeof window !== 'undefined') {\n window.MOJO = window.MOJO || {};\n window.MOJO.VERSION = VERSION;\n window.MOJO.VERSION_INFO = VERSION_INFO;\n\n // Also add to MOJO.version for convenience\n window.MOJO.version = VERSION;\n}\n\nexport default VERSION_INFO;\n"],"names":["VERSION","BUILD_TIME","VERSION_INFO","full","major","minor","revision","buildTime","toString","this","compare","other","parseVer","v","split","map","Number","a1","a2","a3","b1","b2","b3","window","MOJO","version"],"mappings":"aAKY,MAACA,EAAU,QAIVC,EAAa,2BAGbC,EAAe,CACxBC,KAAMH,EACNI,MARyB,EASzBC,MARyB,EASzBC,SAR4B,EAS5BC,UAAWN,EACX,QAAAO,GACI,OAAOC,KAAKN,IAChB,EACA,OAAAO,CAAQC,GACJ,MAAMC,EAAYC,GAAMA,EAAEC,MAAM,KAAKC,IAAIC,SAClCC,EAAIC,EAAIC,GAAMP,EAASH,KAAKN,OAC5BiB,EAAIC,EAAIC,GAAMV,EAASD,GAE9B,OAAIM,IAAOG,EAAWH,EAAKG,EACvBF,IAAOG,EAAWH,EAAKG,EACpBF,EAAKG,CAChB,GAIkB,oBAAXC,SACPA,OAAOC,KAAOD,OAAOC,MAAQ,CAAA,EAC7BD,OAAOC,KAAKxB,QAAUA,EACtBuB,OAAOC,KAAKtB,aAAeA,EAG3BqB,OAAOC,KAAKC,QAAUzB,uFAjCG,wBACA,2BACG"}
1
+ {"version":3,"file":"version-DkxW4rIi.js","sources":["../../src/version.js"],"sourcesContent":["/**\n * MOJO Framework Version Information\n * Auto-generated on 2026-05-01T18:05:48.004Z\n */\n\nexport const VERSION = '2.3.2';\nexport const VERSION_MAJOR = 2;\nexport const VERSION_MINOR = 3;\nexport const VERSION_REVISION = 2;\nexport const BUILD_TIME = '2026-05-01T18:05:48.004Z';\n\n// Version object for easy access\nexport const VERSION_INFO = {\n full: VERSION,\n major: VERSION_MAJOR,\n minor: VERSION_MINOR,\n revision: VERSION_REVISION,\n buildTime: BUILD_TIME,\n toString() {\n return this.full;\n },\n compare(other) {\n const parseVer = (v) => v.split('.').map(Number);\n const [a1, a2, a3] = parseVer(this.full);\n const [b1, b2, b3] = parseVer(other);\n\n if (a1 !== b1) return a1 - b1;\n if (a2 !== b2) return a2 - b2;\n return a3 - b3;\n }\n};\n\n// Make version globally available if in browser\nif (typeof window !== 'undefined') {\n window.MOJO = window.MOJO || {};\n window.MOJO.VERSION = VERSION;\n window.MOJO.VERSION_INFO = VERSION_INFO;\n\n // Also add to MOJO.version for convenience\n window.MOJO.version = VERSION;\n}\n\nexport default VERSION_INFO;\n"],"names":["VERSION","BUILD_TIME","VERSION_INFO","full","major","minor","revision","buildTime","toString","this","compare","other","parseVer","v","split","map","Number","a1","a2","a3","b1","b2","b3","window","MOJO","version"],"mappings":"aAKY,MAACA,EAAU,QAIVC,EAAa,2BAGbC,EAAe,CACxBC,KAAMH,EACNI,MARyB,EASzBC,MARyB,EASzBC,SAR4B,EAS5BC,UAAWN,EACX,QAAAO,GACI,OAAOC,KAAKN,IAChB,EACA,OAAAO,CAAQC,GACJ,MAAMC,EAAYC,GAAMA,EAAEC,MAAM,KAAKC,IAAIC,SAClCC,EAAIC,EAAIC,GAAMP,EAASH,KAAKN,OAC5BiB,EAAIC,EAAIC,GAAMV,EAASD,GAE9B,OAAIM,IAAOG,EAAWH,EAAKG,EACvBF,IAAOG,EAAWH,EAAKG,EACpBF,EAAKG,CAChB,GAIkB,oBAAXC,SACPA,OAAOC,KAAOD,OAAOC,MAAQ,CAAA,EAC7BD,OAAOC,KAAKxB,QAAUA,EACtBuB,OAAOC,KAAKtB,aAAeA,EAG3BqB,OAAOC,KAAKC,QAAUzB,uFAjCG,wBACA,2BACG"}
package/dist/core.css CHANGED
@@ -1427,34 +1427,51 @@ button.dropdown-toggle:has(.multiselect-button-text)::after {
1427
1427
  }
1428
1428
 
1429
1429
  /* ── Card chrome ───────────────────────────────────────── */
1430
- /* Applies to every dialog. NOTE: no overflow:hidden the hero band's
1431
- ::before pseudo-element carries its own matching `border-radius:
1432
- 14px 14px 0 0` (see below) so ancestor clipping isn't needed.
1433
- Keeping overflow visible lets descendant popovers (Bootstrap
1434
- .dropdown-menu, MultiSelectDropdown, ComboBox, context menus)
1435
- escape the card edge instead of being clipped. */
1430
+ /* The default modal eyebrow band is neutral and theme-aware (so it reads as
1431
+ structural chrome, not a status signal). Typed alerts (.modal-alert.*)
1432
+ override --mojo-current-accent / --mojo-current-tint at higher specificity
1433
+ to paint vivid colored bands and tinted card backgrounds.
1434
+
1435
+ --mojo-current-accent → band background color
1436
+ --mojo-current-eyebrow-fg → eyebrow text color
1437
+ --mojo-current-tint → card-background tint (felt across the surface) */
1436
1438
  .modal-content {
1437
- --mojo-current-accent: var(--mojo-dialog-accent);
1438
- border-radius: 14px;
1439
- border: none;
1440
- box-shadow:
1441
- 0 1px 2px rgba(12, 17, 28, 0.06),
1442
- 0 8px 16px -4px rgba(12, 17, 28, 0.1),
1443
- 0 30px 60px -12px rgba(12, 17, 28, 0.28);
1444
- position: relative;
1439
+ --mojo-current-accent: var(--bs-secondary-bg);
1440
+ --mojo-current-eyebrow-fg: var(--bs-secondary-color);
1441
+ --mojo-current-tint: var(--mojo-dialog-accent);
1445
1442
  background:
1446
1443
  linear-gradient(
1447
1444
  180deg,
1448
- color-mix(in srgb, var(--mojo-current-accent) 5%, var(--bs-modal-bg, #fff)) 0%,
1445
+ color-mix(in srgb, var(--mojo-current-tint) 5%, var(--bs-modal-bg, #fff)) 0%,
1449
1446
  var(--bs-modal-bg, #fff) 100%
1450
1447
  );
1451
1448
  }
1452
1449
 
1453
- /* Hero bandsolid colored slab across the top, with the type label
1454
- centered and the close X anchored to the right side. Eyebrow text
1455
- comes from `--mojo-eyebrow` (set inline by each Modal helper). The
1456
- close X is positioned via separate CSS rules below so it can be
1457
- interactive (the band itself stays pointer-events: none). */
1450
+ /* No header/footer dividers the band separates header from body, and the
1451
+ footer's button cluster anchors itself. Removes Bootstrap's 1px lines. */
1452
+ .modal-header { border-bottom: 0; }
1453
+ .modal-footer { border-top: 0; }
1454
+
1455
+ /* Dark mode: Bootstrap ships no modal box-shadow by default, so the card
1456
+ blends into the dark backdrop. Add a soft white inner halo so the edge
1457
+ reads, plus a deep drop shadow so the elevation still feels lifted. The
1458
+ tint mix bumps from 5% → 10% because dark backgrounds absorb color. */
1459
+ [data-bs-theme="dark"] .modal-content {
1460
+ box-shadow:
1461
+ 0 0 0 1px rgba(255, 255, 255, 0.08),
1462
+ 0 24px 48px -12px rgba(0, 0, 0, 0.7);
1463
+ background:
1464
+ linear-gradient(
1465
+ 180deg,
1466
+ color-mix(in srgb, var(--mojo-current-tint) 10%, var(--bs-modal-bg, #14181f)) 0%,
1467
+ var(--bs-modal-bg, #14181f) 100%
1468
+ );
1469
+ }
1470
+
1471
+ /* Hero band — solid colored slab across the top with the eyebrow label
1472
+ centered and the close X anchored to the right. Eyebrow text comes from
1473
+ `--mojo-eyebrow` (set per-modal). The band's top corners track Bootstrap's
1474
+ inner radius so it always matches the card. */
1458
1475
  .modal-content::before {
1459
1476
  content: var(--mojo-eyebrow, "");
1460
1477
  display: flex;
@@ -1467,14 +1484,14 @@ button.dropdown-toggle:has(.multiselect-button-text)::after {
1467
1484
  height: 28px;
1468
1485
  padding: 0 1.5rem;
1469
1486
  background: var(--mojo-current-accent);
1470
- color: #fff;
1487
+ color: var(--mojo-current-eyebrow-fg, #fff);
1471
1488
  font-family: ui-monospace, "JetBrains Mono", "SF Mono", "SFMono-Regular", Menlo, Consolas, monospace;
1472
1489
  font-size: 0.6875rem;
1473
1490
  font-weight: 700;
1474
1491
  letter-spacing: 0.16em;
1475
1492
  text-transform: uppercase;
1476
1493
  line-height: 1;
1477
- border-radius: 14px 14px 0 0;
1494
+ border-radius: var(--bs-modal-inner-border-radius) var(--bs-modal-inner-border-radius) 0 0;
1478
1495
  pointer-events: none;
1479
1496
  z-index: 1;
1480
1497
  box-sizing: border-box;
@@ -1484,9 +1501,6 @@ button.dropdown-toggle:has(.multiselect-button-text)::after {
1484
1501
  root by each Modal helper (alert / confirm / prompt / show / form / etc.).
1485
1502
  No per-type CSS rules needed — every helper passes its own default. */
1486
1503
 
1487
- /* Warning band uses dark text on yellow for AAA contrast */
1488
- .modal.modal-alert.modal-alert-warning .modal-content::before { color: #1a1a1a; }
1489
-
1490
1504
  /* Primary action button picks up the type color so visual hierarchy is
1491
1505
  consistent: red band → red button, green band → green button, etc.
1492
1506
  --mojo-current-accent cascades from .modal-content. */
@@ -1506,29 +1520,18 @@ button.dropdown-toggle:has(.multiselect-button-text)::after {
1506
1520
  --bs-btn-active-color: #1a1a1a;
1507
1521
  }
1508
1522
 
1509
- /* Header — flush against the band, no divider of its own
1510
- (the band + card-bg communicate the boundary). */
1523
+ /* Header — bump just the top padding so content clears the 28px band.
1524
+ Bootstrap's other padding values (sides, bottom) come through unchanged
1525
+ via --bs-modal-header-padding. */
1511
1526
  .modal-header {
1512
- position: relative;
1513
- border-bottom: none;
1514
- border-radius: 14px 14px 0 0;
1515
- background: transparent;
1516
- padding: calc(0.75rem + 28px) 1.5rem 0.5rem;
1517
- }
1518
-
1519
- /* Modal title — when present in the header (i.e. not auto-suppressed
1520
- because it duplicated the eyebrow), render as a bold sans headline. */
1521
- .modal-header .modal-title {
1522
- font-size: 1.125rem;
1523
- font-weight: 700;
1524
- letter-spacing: -0.015em;
1525
- line-height: 1.3;
1526
- margin: 0;
1527
+ padding-top: calc(1rem + 28px);
1527
1528
  }
1528
1529
 
1529
- /* Close X — anchored to the right side of the hero band itself. The
1530
- band has pointer-events: none; the X sits above it (z-index) so
1531
- clicks register. White on most bands; dark on warning. */
1530
+ /* Close X — anchored to the right side of the hero band itself. The band has
1531
+ pointer-events: none; the X sits above it (z-index) so clicks register.
1532
+ Color/hover are left to Bootstrap (dark glyph in light mode, white in dark
1533
+ via [data-bs-theme="dark"]) — typed alerts override below for the colored
1534
+ bands where Bootstrap's default would be too dim. */
1532
1535
  .modal-header .btn-close {
1533
1536
  position: absolute;
1534
1537
  top: 0;
@@ -1540,24 +1543,24 @@ button.dropdown-toggle:has(.multiselect-button-text)::after {
1540
1543
  background-color: transparent;
1541
1544
  background-size: 10px;
1542
1545
  border-radius: 6px;
1543
- opacity: 0.85;
1544
1546
  z-index: 2;
1545
- /* Invert the default Bootstrap close-icon SVG so it's white on
1546
- colored bands. Warning override below restores dark. */
1547
+ }
1548
+
1549
+ /* Typed alerts have a saturated band — force a white X with white-tinted
1550
+ hover/focus so the close button reads against the accent color. */
1551
+ .modal.modal-alert .modal-header .btn-close {
1547
1552
  filter: brightness(0) invert(1);
1548
1553
  transition: opacity 0.15s ease-in-out, background-color 0.15s ease-in-out;
1549
1554
  }
1550
- .modal-header .btn-close:hover {
1551
- opacity: 1;
1555
+ .modal.modal-alert .modal-header .btn-close:hover {
1552
1556
  background-color: rgba(255, 255, 255, 0.18);
1553
1557
  }
1554
- .modal-header .btn-close:focus {
1555
- opacity: 1;
1558
+ .modal.modal-alert .modal-header .btn-close:focus {
1556
1559
  outline: none;
1557
1560
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.6);
1558
1561
  }
1559
1562
 
1560
- /* Warning band uses dark text; restore dark X glyph too */
1563
+ /* Warning band uses dark text restore dark X glyph and dark hover tint */
1561
1564
  .modal.modal-alert.modal-alert-warning .modal-header .btn-close {
1562
1565
  filter: none;
1563
1566
  }
@@ -1565,36 +1568,93 @@ button.dropdown-toggle:has(.multiselect-button-text)::after {
1565
1568
  background-color: rgba(0, 0, 0, 0.1);
1566
1569
  }
1567
1570
 
1568
- /* Footer — clean, no divider line; band/tinted bg already separates regions */
1569
- .modal-content .modal-footer {
1570
- border-top: none;
1571
- padding: 0.5rem 1.5rem 1.25rem;
1572
- }
1573
- .modal-content .modal-body {
1574
- padding: 0.25rem 1.5rem 1rem;
1575
- }
1576
-
1577
1571
  /* Modals without a header still need the band to clear the body padding */
1578
1572
  .modal-content > .modal-body:first-child {
1579
1573
  padding-top: calc(1rem + 28px);
1580
1574
  }
1581
1575
 
1576
+ /* Edge-to-edge body. Caller (ModalView with noBodyPadding) wants body content
1577
+ flush against the modal walls. Top padding is exactly the band height when a
1578
+ band is present so content starts right under the band; zero when bandless. */
1579
+ .modal-content > .modal-body.modal-body-flush {
1580
+ padding: 28px 0 0 0;
1581
+ }
1582
+ .modal.modal-bandless .modal-content > .modal-body.modal-body-flush {
1583
+ padding: 0;
1584
+ }
1585
+ /* Footerless flush body: clip its bottom corners to match Bootstrap's modal
1586
+ inner radius so edge-to-edge content doesn't square off against the rounded
1587
+ .modal-content. (overflow:hidden is scoped to the body itself — popovers from
1588
+ .modal-content can still escape the card.) */
1589
+ .modal-content > .modal-body.modal-body-flush:last-child {
1590
+ border-bottom-left-radius: var(--bs-modal-inner-border-radius);
1591
+ border-bottom-right-radius: var(--bs-modal-inner-border-radius);
1592
+ overflow: hidden;
1593
+ }
1594
+
1595
+ /* Global eyebrow opt-out. Apps that don't want the colored hero band on any
1596
+ modal can set `class="mojo-no-eyebrow"` on <html> or <body>. Mirrors the
1597
+ per-modal `modal-bandless` rules across every .modal. */
1598
+ .mojo-no-eyebrow .modal .modal-content::before { display: none; }
1599
+ .mojo-no-eyebrow .modal .modal-header { padding-top: 1rem; }
1600
+ .mojo-no-eyebrow .modal .modal-content > .modal-body:first-child { padding-top: 1rem; }
1601
+ .mojo-no-eyebrow .modal .modal-content > .modal-body.modal-body-flush { padding: 0; }
1602
+ /* No band → restore Bootstrap's default close button (in-flow, default glyph). */
1603
+ .mojo-no-eyebrow .modal .modal-header .btn-close {
1604
+ position: static;
1605
+ width: 1em;
1606
+ height: 1em;
1607
+ filter: none;
1608
+ background-color: transparent;
1609
+ }
1610
+ [data-bs-theme="dark"] .mojo-no-eyebrow .modal .modal-header .btn-close,
1611
+ [data-bs-theme="dark"].mojo-no-eyebrow .modal .modal-header .btn-close {
1612
+ filter: var(--bs-btn-close-white-filter);
1613
+ }
1614
+
1582
1615
  /* Bandless modals — caller supplied their own header content/view or disabled
1583
- the header entirely. ModalView adds `modal-bandless` to the .modal root in
1584
- those cases. Hide the hero band and drop the band-related top padding so
1585
- custom header chrome paints flush against the rounded top corners. */
1616
+ the band per-modal via `eyebrow: false`. ModalView adds `modal-bandless`
1617
+ to the .modal root. Hide the band, drop the band-related padding, and
1618
+ restore Bootstrap's default close button (otherwise it stays pinned to
1619
+ the corner with a white-on-white filter). */
1586
1620
  .modal.modal-bandless .modal-content::before { display: none; }
1587
- .modal.modal-bandless .modal-header { padding: 0.75rem 1.5rem 0.5rem; }
1621
+ .modal.modal-bandless .modal-header { padding-top: 1rem; }
1588
1622
  .modal.modal-bandless .modal-content > .modal-body:first-child { padding-top: 1rem; }
1623
+ .modal.modal-bandless .modal-header .btn-close {
1624
+ position: static;
1625
+ width: 1em;
1626
+ height: 1em;
1627
+ filter: none;
1628
+ background-color: transparent;
1629
+ }
1630
+ [data-bs-theme="dark"] .modal.modal-bandless .modal-header .btn-close {
1631
+ filter: var(--bs-btn-close-white-filter);
1632
+ }
1589
1633
 
1590
1634
  /* ── Typed alerts ──────────────────────────────────────────
1591
1635
  Root class (modal-alert modal-alert-{type}) is set by Modal.alert.
1592
- Each type swaps --mojo-current-accent on .modal-content; everything else
1593
- (band, tinted bg, focus ring, primary buttons) reads from that token. */
1636
+ Each type swaps --mojo-current-accent (band/button color) and
1637
+ --mojo-current-eyebrow-fg (eyebrow text). Default modals stay neutral. */
1594
1638
 
1595
- .modal.modal-alert.modal-alert-success .modal-content { --mojo-current-accent: var(--mojo-dialog-success); }
1596
- .modal.modal-alert.modal-alert-warning .modal-content { --mojo-current-accent: var(--mojo-dialog-warning); }
1597
- .modal.modal-alert.modal-alert-error .modal-content { --mojo-current-accent: var(--mojo-dialog-error); }
1639
+ .modal.modal-alert .modal-content {
1640
+ --mojo-current-accent: var(--mojo-dialog-accent);
1641
+ --mojo-current-eyebrow-fg: #fff;
1642
+ /* tint defaults to --mojo-dialog-accent already; explicit for typed
1643
+ alerts below where band and tint share the same type token */
1644
+ }
1645
+ .modal.modal-alert.modal-alert-success .modal-content {
1646
+ --mojo-current-accent: var(--mojo-dialog-success);
1647
+ --mojo-current-tint: var(--mojo-dialog-success);
1648
+ }
1649
+ .modal.modal-alert.modal-alert-warning .modal-content {
1650
+ --mojo-current-accent: var(--mojo-dialog-warning);
1651
+ --mojo-current-tint: var(--mojo-dialog-warning);
1652
+ --mojo-current-eyebrow-fg: #1a1a1a;
1653
+ }
1654
+ .modal.modal-alert.modal-alert-error .modal-content {
1655
+ --mojo-current-accent: var(--mojo-dialog-error);
1656
+ --mojo-current-tint: var(--mojo-dialog-error);
1657
+ }
1598
1658
 
1599
1659
  /* Title typography for typed alerts — eyebrow micro-label above headline.
1600
1660
  Both spans live inside Bootstrap's <h5 class="modal-title"> wrapper; we
@@ -1634,50 +1694,15 @@ button.dropdown-toggle:has(.multiselect-button-text)::after {
1634
1694
  }
1635
1695
 
1636
1696
  /* ── Dark mode ─────────────────────────────────────────────
1637
- Brighter accents read against dark surfaces; tint bumped 5% → 10%
1638
- because dark backgrounds absorb color. */
1697
+ Brighter accent tokens read against dark surfaces. The modal box-shadow
1698
+ is also adjusted in dark mode (see the .modal-content rule near the top)
1699
+ so the card doesn't blend into the dark backdrop. */
1639
1700
  @media (prefers-color-scheme: dark) {
1640
1701
  :root {
1641
1702
  --mojo-dialog-success: #4ade80;
1642
1703
  --mojo-dialog-warning: #fbbf24;
1643
1704
  --mojo-dialog-error: #f87171;
1644
1705
  }
1645
- .modal-content {
1646
- box-shadow:
1647
- 0 1px 0 rgba(0, 0, 0, 0.4),
1648
- 0 24px 60px -16px rgba(0, 0, 0, 0.6);
1649
- background:
1650
- linear-gradient(
1651
- 180deg,
1652
- color-mix(in srgb, var(--mojo-current-accent) 10%, var(--bs-modal-bg, #14181f)) 0%,
1653
- var(--bs-modal-bg, #14181f) 100%
1654
- );
1655
- }
1656
- .modal-header {
1657
- border-bottom-color: rgba(255, 255, 255, 0.08);
1658
- }
1659
- .modal-header .btn-close:hover {
1660
- background-color: rgba(255, 255, 255, 0.08);
1661
- }
1662
- }
1663
-
1664
- /* Same rules under explicit Bootstrap dark theme attribute */
1665
- [data-bs-theme="dark"] .modal-content {
1666
- box-shadow:
1667
- 0 1px 0 rgba(0, 0, 0, 0.4),
1668
- 0 24px 60px -16px rgba(0, 0, 0, 0.6);
1669
- background:
1670
- linear-gradient(
1671
- 180deg,
1672
- color-mix(in srgb, var(--mojo-current-accent) 10%, var(--bs-modal-bg, #14181f)) 0%,
1673
- var(--bs-modal-bg, #14181f) 100%
1674
- );
1675
- }
1676
- [data-bs-theme="dark"] .modal-header {
1677
- border-bottom-color: rgba(255, 255, 255, 0.08);
1678
- }
1679
- [data-bs-theme="dark"] .modal-header .btn-close:hover {
1680
- background-color: rgba(255, 255, 255, 0.08);
1681
1706
  }
1682
1707
 
1683
1708
  /* ========================================================================