@aiquants/menu-bar 1.18.2 → 1.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MenuBar.d.ts +2 -29
- package/dist/components/SessionInfo.d.ts +1 -26
- package/dist/contents/MenuContent.d.ts +2 -14
- package/dist/contents/MenuList.d.ts +0 -38
- package/dist/contents/OverlayShadow.d.ts +0 -19
- package/dist/elements/MenuSwitch.d.ts +1 -10
- package/dist/events/pinEvent.d.ts +2 -37
- package/dist/hooks/useMenuPinState.d.ts +1 -16
- package/dist/index.d.ts +11 -21
- package/dist/index.es.js +170 -170
- package/dist/index.umd.js +2 -2
- package/dist/types/user.d.ts +0 -7
- package/dist/types.d.ts +1 -15
- package/package.json +2 -3
- package/dist/__tests__/pinEvent.test.d.ts +0 -1
- package/src/MenuBar.tsx +0 -248
- package/src/__tests__/pinEvent.test.tsx +0 -68
- package/src/components/SessionInfo.tsx +0 -95
- package/src/contents/MenuContent.tsx +0 -79
- package/src/contents/MenuList.tsx +0 -400
- package/src/contents/OverlayShadow.tsx +0 -30
- package/src/elements/MenuSwitch.tsx +0 -134
- package/src/events/pinEvent.ts +0 -129
- package/src/hooks/useMenuPinState.ts +0 -58
- package/src/index.ts +0 -29
- package/src/lucide-icons.d.ts +0 -6
- package/src/styles/components.entry.css +0 -11
- package/src/styles/menu-bar.css +0 -224
- package/src/styles/standalone.entry.css +0 -12
- package/src/types/user.ts +0 -12
- package/src/types.ts +0 -24
package/dist/index.umd.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(S,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("react"),require("react-router-dom")):typeof define=="function"&&define.amd?define(["exports","react","react-router-dom"],o):(S=typeof globalThis<"u"?globalThis:S||self,o(S["@aiquants/menu-bar"]={},S.React,S.ReactRouterDOM))})(this,(function(S,o,B){"use strict";var U={exports:{}},D={};var oe;function ye(){if(oe)return D;oe=1;var n=Symbol.for("react.transitional.element"),t=Symbol.for("react.fragment");function s(a,c,i){var d=null;if(i!==void 0&&(d=""+i),c.key!==void 0&&(d=""+c.key),"key"in c){i={};for(var p in c)p!=="key"&&(i[p]=c[p])}else i=c;return c=i.ref,{$$typeof:n,type:a,key:d,ref:c!==void 0?c:null,props:i}}return D.Fragment=t,D.jsx=s,D.jsxs=s,D}var Y={};var ie;function ke(){return ie||(ie=1,process.env.NODE_ENV!=="production"&&(function(){function n(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ne?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case h:return"Fragment";case I:return"Profiler";case P:return"StrictMode";case H:return"Suspense";case ee:return"SuspenseList";case W:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case l:return"Portal";case R:return e.displayName||"Context";case v:return(e._context.displayName||"Context")+".Consumer";case L:var u=e.render;return e=e.displayName,e||(e=u.displayName||u.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case te:return u=e.displayName||null,u!==null?u:n(e.type)||"Memo";case V:u=e._payload,e=e._init;try{return n(e(u))}catch{}}return null}function t(e){return""+e}function s(e){try{t(e);var u=!1}catch{u=!0}if(u){u=console;var g=u.error,_=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return g.call(u,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",_),t(e)}}function a(e){if(e===h)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===V)return"<...>";try{var u=n(e);return u?"<"+u+">":"<...>"}catch{return"<...>"}}function c(){var e=O.A;return e===null?null:e.getOwner()}function i(){return Error("react-stack-top-frame")}function d(e){if(Z.call(e,"key")){var u=Object.getOwnPropertyDescriptor(e,"key").get;if(u&&u.isReactWarning)return!1}return e.key!==void 0}function p(e,u){function g(){F||(F=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",u))}g.isReactWarning=!0,Object.defineProperty(e,"key",{get:g,configurable:!0})}function m(){var e=n(this.type);return k[e]||(k[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function b(e,u,g,_,q,se){var j=g.ref;return e={$$typeof:x,type:e,key:u,props:g,_owner:_},(j!==void 0?j:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:m}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:q}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:se}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function f(e,u,g,_,q,se){var j=u.children;if(j!==void 0)if(_)if(re(j)){for(_=0;_<j.length;_++)N(j[_]);Object.freeze&&Object.freeze(j)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else N(j);if(Z.call(u,"key")){j=n(e);var z=Object.keys(u).filter(function(qe){return qe!=="key"});_=0<z.length?"{key: someKey, "+z.join(": ..., ")+": ...}":"{key: someKey}",J[j+_]||(z=0<z.length?"{"+z.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
|
|
2
2
|
let props = %s;
|
|
3
3
|
<%s {...props} />
|
|
4
4
|
React keys must be passed directly to JSX without using spread:
|
|
5
5
|
let props = %s;
|
|
6
|
-
<%s key={someKey} {...props} />`,_,j,z,j),J[j+_]=!0)}if(j=null,p!==void 0&&(s(p),j=""+p),d(u)&&(s(u.key),j=""+u.key),"key"in u){p={};for(var ae in u)ae!=="key"&&(p[ae]=u[ae])}else p=u;return j&&g(p,typeof e=="function"?e.displayName||e.name||"Unknown":e),w(e,j,p,c(),q,se)}function N(e){v(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===V&&(e._payload.status==="fulfilled"?v(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function v(e){return typeof e=="object"&&e!==null&&e.$$typeof===m}var b=a,m=Symbol.for("react.transitional.element"),l=Symbol.for("react.portal"),h=Symbol.for("react.fragment"),P=Symbol.for("react.strict_mode"),A=Symbol.for("react.profiler"),x=Symbol.for("react.consumer"),I=Symbol.for("react.context"),L=Symbol.for("react.forward_ref"),H=Symbol.for("react.suspense"),ee=Symbol.for("react.suspense_list"),te=Symbol.for("react.memo"),V=Symbol.for("react.lazy"),W=Symbol.for("react.activity"),ne=Symbol.for("react.client.reference"),R=b.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,Z=Object.prototype.hasOwnProperty,re=Array.isArray,T=console.createTask?console.createTask:function(){return null};b={react_stack_bottom_frame:function(e){return e()}};var F,y={},C=b.react_stack_bottom_frame.bind(b,i)(),O=T(o(i)),J={};Y.Fragment=h,Y.jsx=function(e,u,p){var _=1e4>R.recentlyCreatedOwnerStacks++;return f(e,u,p,!1,_?Error("react-stack-top-frame"):C,_?T(o(e)):O)},Y.jsxs=function(e,u,p){var _=1e4>R.recentlyCreatedOwnerStacks++;return f(e,u,p,!0,_?Error("react-stack-top-frame"):C,_?T(o(e)):O)}})()),Y}var le;function we(){return le||(le=1,process.env.NODE_ENV==="production"?U.exports=ke():U.exports=ve()),U.exports}var r=we();const Ne=n=>n.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),_e=n=>n.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,s,o)=>o?o.toUpperCase():s.toLowerCase()),ce=n=>{const t=_e(n);return t.charAt(0).toUpperCase()+t.slice(1)},ue=(...n)=>n.filter((t,s,o)=>!!t&&t.trim()!==""&&o.indexOf(t)===s).join(" ").trim(),je=n=>{for(const t in n)if(t.startsWith("aria-")||t==="role"||t==="title")return!0};var Ee={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};const Se=a.forwardRef(({color:n="currentColor",size:t=24,strokeWidth:s=2,absoluteStrokeWidth:o,className:c="",children:i,iconNode:d,...g},k)=>a.createElement("svg",{ref:k,...Ee,width:t,height:t,stroke:n,strokeWidth:o?Number(s)*24/Number(t):s,className:ue("lucide",c),...!i&&!je(g)&&{"aria-hidden":"true"},...g},[...d.map(([w,f])=>a.createElement(w,f)),...Array.isArray(i)?i:[i]]));const M=(n,t)=>{const s=a.forwardRef(({className:o,...c},i)=>a.createElement(Se,{ref:i,iconNode:t,className:ue(`lucide-${Ne(ce(n))}`,`lucide-${n}`,o),...c}));return s.displayName=ce(n),s};const Ce=M("external-link",[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]]);const Me=M("user",[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]]),Pe="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2NiZDVlMSI+PHBhdGggZD0iTTEyIDEyYzIuMjEgMCA0LTEuNzkgNC00cy0xLjc5LTQtNC00LTQgMS43OS00IDQgMS43OSA0IDQgNHptMCAyYy0yLjY3IDAtOCAxLjM0LTggNHYyaDE2di0yYzAtMi42Ni01LjMzLTQtOC00eiIvPjwvc3ZnPg==",de=({to:n,className:t,children:s})=>r.jsx("a",{href:n,className:t,children:s}),Re=n=>{const{user:t,LinkComponent:s=de}=n;return r.jsx("div",{className:"w-full",children:t?r.jsxs("div",{className:"aiquants-session-card group relative flex flex-col gap-2 rounded-xl border border-white/20 bg-white/10 p-2.5 shadow-sm backdrop-blur-md transition-all duration-200 hover:border-white/30 hover:bg-white/15 dark:border-slate-700/60 dark:bg-slate-800/60 dark:hover:border-slate-600/80 dark:hover:bg-slate-800/90",children:[r.jsxs("div",{className:"flex min-w-0 items-center gap-2.5",children:[r.jsxs("div",{className:"relative shrink-0",children:[r.jsx("div",{className:"h-8 w-8 overflow-hidden rounded-full border border-white/40 shadow-xs dark:border-slate-500",children:r.jsx("img",{className:"h-full w-full rounded-full object-cover",src:t.photo||Pe,alt:t.displayName||"user profile"})}),r.jsx("span",{className:"absolute -right-0.5 -bottom-0.5 h-2.5 w-2.5 rounded-full border-2 border-slate-900 bg-emerald-400",title:"Online"})]}),r.jsxs("div",{className:"min-w-0 flex-1 leading-tight",children:[r.jsx("div",{className:"truncate font-semibold text-white text-xs tracking-tight dark:text-slate-100",title:t.displayName,children:t.displayName}),r.jsx("div",{className:"mt-0.5 font-medium text-[10px] text-white/75 tracking-tight dark:text-slate-400",children:"Google Account"})]})]}),r.jsxs("div",{className:"grid grid-cols-2 gap-1.5 border-white/15 border-t pt-1.5 dark:border-slate-700/50",children:[r.jsxs(s,{className:"flex items-center justify-center gap-1 rounded-md border border-white/15 bg-white/10 px-2 py-1 font-medium text-[11px] text-white transition-all duration-150 hover:bg-white/25 active:scale-95 dark:border-slate-600/50 dark:bg-slate-700/50 dark:text-slate-200 dark:hover:bg-slate-600/80",to:"/",children:[r.jsx(Me,{size:11,className:"shrink-0 opacity-80"}),r.jsx("span",{className:"truncate",children:"プロフィール"})]}),r.jsxs(s,{className:"flex items-center justify-center gap-1 rounded-md border border-white/15 bg-white/10 px-2 py-1 font-medium text-[11px] text-white transition-all duration-150 hover:bg-white/25 active:scale-95 dark:border-slate-600/50 dark:bg-slate-700/50 dark:text-slate-200 dark:hover:bg-slate-600/80",to:"https://myaccount.google.com/",children:[r.jsx(Ce,{size:11,className:"shrink-0 opacity-80"}),r.jsx("span",{className:"truncate",children:"Google"})]})]})]}):r.jsx("div",{className:"aiquants-session-card flex items-center justify-between rounded-xl border border-white/20 bg-white/10 p-2.5 shadow-xs dark:border-slate-700/60 dark:bg-slate-800/60",children:r.jsx("span",{className:"font-medium text-white/90 text-xs dark:text-slate-200",children:"ログインしてください"})})})},G="aiquants-menu-pin-change";let S={pinned:!1,width:0};const Q=(n=240)=>{if(typeof window>"u"||typeof document>"u")return{pinned:!1,width:0};try{const t=getComputedStyle(document.documentElement).getPropertyValue("--aiquants-menu-pinned-width").trim();if(t){const i=Number.parseInt(t,10);if(!Number.isNaN(i)){const d=i>0,g=d?i||n:0;return S.pinned===d&&S.width===g||(S={pinned:d,width:g}),S}}const o=localStorage.getItem("aiquants-menu-pinned")==="true",c=o?n:0;return S.pinned===o&&S.width===c||(S={pinned:o,width:c}),S}catch{return{pinned:!1,width:0}}},X=(n,t)=>{if(typeof window>"u")return;const s={pinned:n,width:t};(S.pinned!==n||S.width!==t)&&(S=s);const o=new CustomEvent(G,{detail:s,bubbles:!0,cancelable:!1});window.dispatchEvent(o)},fe=(n,t)=>{if(typeof window>"u")return()=>{};const{immediate:s=!0,defaultPinnedWidth:o=240}=t??{};if(s){const i=Q(o);n(i)}const c=i=>{const d=i;d.detail&&n(d.detail)};return window.addEventListener(G,c,{passive:!0}),()=>{window.removeEventListener(G,c)}},Te=n=>{const t=n?.defaultPinnedWidth??240,s=n?.initialPinned??!1,o=a.useCallback(d=>fe(()=>{d()},{immediate:!1,defaultPinnedWidth:t}),[t]),c=a.useCallback(()=>Q(t),[t]),i=a.useCallback(()=>({pinned:s,width:s?t:0}),[s,t]);return a.useSyncExternalStore(o,c,i)};const Oe=M("log-out",[["path",{d:"m16 17 5-5-5-5",key:"1bji2h"}],["path",{d:"M21 12H9",key:"dn1m92"}],["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}]]);const he=M("pin",[["path",{d:"M12 17v5",key:"bb1du9"}],["path",{d:"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z",key:"1nkz8b"}]]);const me=M("pin-off",[["path",{d:"M12 17v5",key:"bb1du9"}],["path",{d:"M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89",key:"znwnzq"}],["path",{d:"m2 2 20 20",key:"1ooewy"}],["path",{d:"M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h11",key:"c9qhm2"}]]);const Ae=M("chart-no-axes-column-increasing",[["path",{d:"M5 21v-6",key:"1hz6c0"}],["path",{d:"M12 21V9",key:"uvy0l4"}],["path",{d:"M19 21V3",key:"11j9sm"}]]);const Ie=M("download",[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]]);const pe=M("file-text",[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]]);const Le=M("link",[["path",{d:"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71",key:"1cjeqo"}],["path",{d:"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71",key:"19qd67"}]]);const ze=M("lock",[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]]);const De=M("table",[["path",{d:"M12 3v18",key:"108xh3"}],["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M3 9h18",key:"1pudct"}],["path",{d:"M3 15h18",key:"5xshup"}]]),Ye=typeof window<"u"?a.useLayoutEffect:a.useEffect,be="aiquants-menu-scroll",xe=new RegExp(/(^https?:\/\/)|(\.(html|htm)?$)/),He={report:pe,slip:pe,table:De,chart:Ae,download:Ie,lock:ze,href:Le},Ve=({mark:n,children:t})=>{const s=n?He[n]:void 0;return s?r.jsxs("div",{className:"flex flex-nowrap items-center",children:[r.jsx(s,{className:"h-3.5 w-3.5 shrink-0"}),r.jsx("div",{className:"aiquants-menu-link mx-1 hover:underline",children:t})]}):r.jsx("span",{className:"mx-1 text-sky-600 hover:underline dark:text-sky-400",children:t})},K=(n,t)=>t?{menu:{id:n.id,title:n.title,href:n.href},submenu:{subid:t.subid,title:t.title,href:t.href,mark:t.mark,new:t.new}}:{menu:{id:n.id,title:n.title,href:n.href}},We=({item:n,parentMenu:t,onMenuSelected:s})=>{if(n.href==="separator")return r.jsx("hr",{className:"aiquants-menu-separator mx-2 my-1 h-px"});const o=r.jsx(Ve,{mark:n.mark,children:n.title}),c={onClick:()=>{s&&s(K(t,n))}};return n.new?r.jsx("a",{href:n.href,rel:"noopener noreferrer",target:"_blank",...c,children:o}):xe.test(n.href)?r.jsx("a",{href:n.href,...c,children:o}):r.jsx(B.Link,{to:n.href,...c,children:o})},ye=n=>n?n.split(/[?#]/)[0].replace(/(?!^\/)\/$/,""):"",ge=(n,t)=>{const s=t!=="/"&&t.endsWith("/")?t.slice(0,-1):t;for(const o of n){if(ye(o.href)===s)return o.id;if(o.submenu){for(const c of o.submenu)if(ye(c.href)===s)return o.id}}return null},Fe=n=>{const{menuList:t,onMenuSelected:s,pinnedSubmenuIds:o=[],onToggleSubmenuPin:c}=n;let i="";try{i=B.useLocation().pathname}catch{typeof window<"u"&&(i=window.location.pathname)}const d=a.useMemo(()=>ge(t,i),[t,i]),[g,k]=a.useState(d),w=a.useRef(i),f=a.useRef(d!==null);a.useEffect(()=>{if(w.current!==i&&(w.current=i,f.current=!1),!f.current){const l=ge(t,i);l!==null&&(k(l),f.current=!0)}},[i,t]);const N=a.useCallback(l=>{o.includes(l)||k(P=>P===l?null:l)},[o]),v=a.useRef(null);Ye(()=>{const l=v.current;if(l)try{const h=sessionStorage.getItem(be);if(h!==null){const P=Number.parseFloat(h);Number.isNaN(P)||(l.scrollTop=P)}}catch{}},[]);const b=a.useCallback(()=>{const l=v.current;if(l)try{sessionStorage.setItem(be,String(l.scrollTop))}catch{}},[]),m=a.useMemo(()=>r.jsx(r.Fragment,{children:t.map(l=>r.jsx("div",{children:l.href?r.jsx("div",{className:"aiquants-menu-list-item relative mb-0.5 ml-1 flex items-center rounded-l-xl px-2.5 py-1 text-xs before:mr-2 before:inline-block before:h-2 before:w-2 before:shrink-0 before:rounded-full before:content-[''] sm:text-sm",children:xe.test(l.href)?r.jsx("a",{href:l.href,onClick:()=>{s&&s(K(l))},children:r.jsx("span",{className:"aiquants-menu-link hover:underline",children:l.title})}):r.jsx(B.Link,{to:l.href,onClick:()=>{s&&s(K(l))},children:r.jsx("span",{className:"aiquants-menu-link hover:underline",children:l.title})})}):r.jsxs("details",{className:"aiquants-menu-accordion-details",open:l.id===g||o.includes(l.id),children:[r.jsxs("summary",{className:"aiquants-menu-list-item aiquants-menu-accordion-summary relative mb-0.5 ml-1 list-none rounded-l-xl px-2.5 py-1 text-xs outline-none before:mr-2 before:inline-block before:h-2 before:w-2 before:shrink-0 before:rounded-full before:content-[''] sm:text-sm",onClick:h=>{h.preventDefault(),N(l.id)},onKeyDown:h=>{(h.key==="Enter"||h.key===" ")&&(h.preventDefault(),N(l.id))},children:[r.jsx("span",{children:l.title}),r.jsx("button",{type:"button",onClick:h=>{h.stopPropagation(),h.preventDefault(),c&&c(l.id)},className:`aiquants-submenu-pin-button ${o.includes(l.id)?"pinned":""}`,title:o.includes(l.id)?"ピン留め解除":"ピン留め",children:o.includes(l.id)?r.jsx(he,{size:13}):r.jsx(me,{size:13})})]}),r.jsx("div",{className:"aiquants-menu-submenu pointer-events-auto my-0.5 mr-1 ml-3.5 rounded-lg px-2 py-1 shadow-sm",children:l.submenu.map(h=>r.jsx("div",{className:"aiquants-menu-accordion-container block w-full whitespace-nowrap py-0.5 text-xs",children:r.jsx(We,{item:h,parentMenu:l,onMenuSelected:s})},h.subid))})]})},l.id))}),[t,s,g,N,o]);return r.jsx("div",{ref:v,onScroll:b,className:"hidden-scrollbar h-0 grow overflow-y-scroll",children:m})},Ue=n=>{const{menuList:t,menuHeader:s,open:o,onMenuSelected:c,onClickSignout:i,theme:d,toggleTheme:g,isPinned:k,onTogglePin:w,pinnedSubmenuIds:f,onToggleSubmenuPin:N}=n;return r.jsxs("div",{className:`aiquants-menu-content fixed top-0 right-0 z-2147483642 flex min-h-dvh w-[240px] select-none flex-col transition-transform duration-500 ${o?"aiquants-menu-translate-x-0":"aiquants-menu-translate-x-250"}`,children:[r.jsx("div",{className:"flex shrink-0 flex-col justify-center border-white/15 border-b px-2.5 py-2 dark:border-slate-700/60",children:s}),r.jsx("div",{className:"flex grow flex-col overflow-y-auto",children:r.jsx(Fe,{menuList:t,onMenuSelected:c,pinnedSubmenuIds:f,onToggleSubmenuPin:N})}),r.jsx("div",{className:"border-white/15 border-t px-2.5 py-1.5 dark:border-slate-700/60",children:r.jsxs("div",{className:"flex items-center justify-between gap-1.5",children:[r.jsx("button",{type:"button",onClick:w,"data-aqmb-pin-button":!0,className:`flex h-7 items-center justify-center rounded-md px-2 text-[11px] text-white shadow-2xs transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-300/60 ${k?"bg-amber-500 hover:bg-amber-600 dark:bg-amber-600 dark:hover:bg-amber-500":"border border-white/20 bg-white/10 hover:bg-white/20 dark:border-slate-600/60 dark:bg-slate-700/60 dark:hover:bg-slate-600"}`,title:k?"ピン留め解除":"ピン留め","aria-label":k?"ピン留め解除":"ピン留め",children:k?r.jsx(he,{size:12}):r.jsx(me,{size:12})}),r.jsx("button",{type:"button",onClick:g,"data-aqmb-theme-button":!0,className:"group relative flex h-7 items-center justify-center rounded-md border border-white/20 bg-white/10 px-2 text-[11px] text-white shadow-2xs backdrop-blur-xs transition-all duration-200 hover:bg-white/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 dark:border-slate-600/60 dark:bg-slate-700/60 dark:hover:bg-slate-600",title:d==="dark"?"ライトモードに切り替え":"ダークモードに切り替え","aria-label":d==="dark"?"ライトモードに切り替え":"ダークモードに切り替え",children:r.jsx("span",{className:"text-xs transition-transform duration-200 group-hover:scale-110",children:d==="dark"?"🌞":"🌙"})}),r.jsxs("button",{type:"button","data-aqmb-signout-button":!0,className:"aiquants-signout-button flex h-7 flex-1 items-center justify-center gap-1.5 whitespace-nowrap rounded-md bg-red-500/90 px-2.5 font-medium text-[11px] text-white shadow-2xs transition-colors duration-200 hover:bg-red-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-300/60 dark:bg-red-600/90 dark:hover:bg-red-500",onClick:i,children:[r.jsx(Oe,{size:11,className:"shrink-0"}),r.jsx("span",{children:"サインアウト"})]})]})})]})},Ge=n=>{const{isOverlay:t,onOverlayClick:s}=n;return r.jsx("button",{type:"button",className:`fixed inset-0 z-2147483640 cursor-default bg-black/50 transition-opacity duration-500 ${t?"opacity-100":"pointer-events-none opacity-0"}`,onClick:s})},Ze=n=>{const{open:t,isOpen:s,onMenuOpen:o,onMenuClose:c,onToggle:i,theme:d="light",className:g}=n,k=t??(s!==void 0?!s:!0),w=a.useRef(k),f=a.useRef(null),N=a.useRef(null),v=a.useRef(null),b=a.useRef(null),m=a.useRef(null),l=a.useCallback(()=>{if(f.current&&N.current&&v.current&&b.current&&m.current){const x=d==="dark"?"#fff":"#000";f.current.style.backgroundColor=x,f.current.style.width="100%",f.current.style.height="3px",f.current.style.transform="none",N.current.style.opacity="1",N.current.style.backgroundColor=x,v.current.style.opacity="1",v.current.style.backgroundColor=x,b.current.style.backgroundColor=x,b.current.style.width="100%",b.current.style.height="3px",b.current.style.transform="none",m.current.style.color=x,m.current.classList.remove("after:content-['close']"),m.current.classList.remove("after:ml-0.5"),m.current.classList.add("after:content-['menu']"),m.current.classList.add("after:-ml-0.5"),w.current=!0}},[d]),h=a.useCallback(()=>{f.current&&N.current&&v.current&&b.current&&m.current&&(f.current.style.backgroundColor="#fff",f.current.style.width="32px",f.current.style.height="4px",f.current.style.transform="translateY(9px) rotate(-45deg)",N.current.style.opacity="0",v.current.style.opacity="0",b.current.style.backgroundColor="#fff",b.current.style.width="32px",b.current.style.height="4px",b.current.style.transform="translateY(-9px) rotate(45deg)",m.current.style.color="#fff",m.current.classList.remove("after:content-['menu']"),m.current.classList.remove("after:-ml-0.5"),m.current.classList.add("after:content-['close']"),m.current.classList.add("after:ml-0.5"),w.current=!1)},[]);a.useEffect(()=>{k?l():h()},[k,l,h]);const P=a.useCallback(()=>{w.current?(h(),o?.(),i?.(!0)):(l(),c?.(),i?.(!1))},[h,l,o,c,i]),A=!k;return r.jsxs("button",{type:"button","data-aqmb-menu-switch":"true","aria-label":A?"Close menu":"Open menu","aria-expanded":A,className:`aiquants-menu-switch z-[2147483647] inline-block h-[27px] w-[27px] cursor-pointer align-middle outline-hidden ${g||""}`,onClick:P,children:[r.jsx("span",{ref:f,className:"absolute top-0 left-0 box-border inline-block h-[3px] w-full select-none transition-all duration-500"}),r.jsx("span",{ref:N,className:"absolute top-[6px] left-0 box-border inline-block h-[3px] w-full select-none transition-all duration-500"}),r.jsx("span",{ref:v,className:"absolute top-[12px] left-0 box-border inline-block h-[3px] w-full select-none transition-all duration-500"}),r.jsx("span",{ref:b,className:"absolute top-[18px] left-0 box-border inline-block h-[3px] w-full select-none transition-all duration-500"}),r.jsx("div",{ref:m,className:"absolute w-full text-xs transition-all duration-500 after:mt-2 after:block"})]})},$=typeof window<"u"?a.useLayoutEffect:a.useEffect,Je=n=>{const{menuList:t,menuHeader:s,onClickSignout:o,isMenuhide:c,isMenuHide:i,theme:d,toggleTheme:g,onMenuNavigate:k,isPinned:w,pinnedWidth:f=240,onPinChange:N,pinnedSubmenuIds:v,initialPinnedSubmenuIds:b,onSubmenuPinChange:m,closeOnEscape:l="auto"}=n,h=i??c??!1,[P,A]=a.useState(()=>{try{return localStorage.getItem("aiquants-menu-pinned")==="true"}catch{return!1}}),x=w!==void 0?w:P,[I,L]=a.useState(x);a.useEffect(()=>{x&&L(!0)},[x]);const[H,ee]=a.useState(()=>{if(b)return b;try{const y=localStorage.getItem("aiquants-submenu-pinned");if(y){const C=JSON.parse(y);if(Array.isArray(C))return C.filter(O=>typeof O=="number")}}catch{}return[]}),te=v!==void 0?v:H,V=a.useCallback(y=>{const C=v!==void 0?v:H,O=C.includes(y)?C.filter(J=>J!==y):[...C,y];if(v===void 0){ee(O);try{localStorage.setItem("aiquants-submenu-pinned",JSON.stringify(O))}catch{}}m&&m(O)},[v,H,m]),W=a.useRef(N);$(()=>{W.current=N},[N]),$(()=>{const y=x?f:0,C=`${y}px`;document.documentElement.style.setProperty("--aiquants-menu-pinned-width",C),X(x,y)},[x,f]),$(()=>()=>{document.documentElement.style.setProperty("--aiquants-menu-pinned-width","0px"),X(!1,0)},[]);const ne=a.useCallback(()=>{L(!0)},[]),R=a.useCallback(()=>{if(L(!1),w===void 0){A(!1);try{localStorage.removeItem("aiquants-menu-pinned")}catch{}}W.current?.(!1,0)},[w]),Z=a.useCallback(()=>{const y=!x,C=y?f:0;if(w===void 0){A(y);try{y?localStorage.setItem("aiquants-menu-pinned","true"):localStorage.removeItem("aiquants-menu-pinned")}catch{}}W.current?.(y,C)},[x,w,f]),re=a.useCallback(y=>{k&&k(y),x||L(!1)},[k,x]),T=a.useCallback(y=>{y.key==="Escape"&&R()},[R]),F=l===!0||l==="auto"&&!x;return a.useEffect(()=>(I&&F?window.addEventListener("keydown",T):window.removeEventListener("keydown",T),()=>{window.removeEventListener("keydown",T)}),[I,F,T]),h?null:r.jsxs("div",{className:`aiquants-menu-bar ${d}`,children:[r.jsx(Ze,{onMenuClose:R,onMenuOpen:ne,open:!I,theme:d}),r.jsx(Ue,{menuList:t,menuHeader:s,onClickSignout:o,onMenuSelected:re,open:I,theme:d,toggleTheme:g,isPinned:x,onTogglePin:Z,pinnedSubmenuIds:te,onToggleSubmenuPin:V}),r.jsx(Ge,{isOverlay:I&&!x,onOverlayClick:R})]})};E.DefaultLink=de,E.MENU_PIN_CHANGE_EVENT=G,E.MenuBar=Je,E.SessionInfo=Re,E.dispatchMenuPinChange=X,E.getInitialPinState=Q,E.subscribeMenuPinChange=fe,E.useMenuPinState=Te,Object.defineProperty(E,Symbol.toStringTag,{value:"Module"})}));
|
|
6
|
+
<%s key={someKey} {...props} />`,_,j,z,j),J[j+_]=!0)}if(j=null,g!==void 0&&(s(g),j=""+g),d(u)&&(s(u.key),j=""+u.key),"key"in u){g={};for(var ae in u)ae!=="key"&&(g[ae]=u[ae])}else g=u;return j&&p(g,typeof e=="function"?e.displayName||e.name||"Unknown":e),b(e,j,g,c(),q,se)}function N(e){w(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===V&&(e._payload.status==="fulfilled"?w(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function w(e){return typeof e=="object"&&e!==null&&e.$$typeof===x}var y=o,x=Symbol.for("react.transitional.element"),l=Symbol.for("react.portal"),h=Symbol.for("react.fragment"),P=Symbol.for("react.strict_mode"),I=Symbol.for("react.profiler"),v=Symbol.for("react.consumer"),R=Symbol.for("react.context"),L=Symbol.for("react.forward_ref"),H=Symbol.for("react.suspense"),ee=Symbol.for("react.suspense_list"),te=Symbol.for("react.memo"),V=Symbol.for("react.lazy"),W=Symbol.for("react.activity"),ne=Symbol.for("react.client.reference"),O=y.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,Z=Object.prototype.hasOwnProperty,re=Array.isArray,A=console.createTask?console.createTask:function(){return null};y={react_stack_bottom_frame:function(e){return e()}};var F,k={},C=y.react_stack_bottom_frame.bind(y,i)(),T=A(a(i)),J={};Y.Fragment=h,Y.jsx=function(e,u,g){var _=1e4>O.recentlyCreatedOwnerStacks++;return f(e,u,g,!1,_?Error("react-stack-top-frame"):C,_?A(a(e)):T)},Y.jsxs=function(e,u,g){var _=1e4>O.recentlyCreatedOwnerStacks++;return f(e,u,g,!0,_?Error("react-stack-top-frame"):C,_?A(a(e)):T)}})()),Y}var le;function we(){return le||(le=1,process.env.NODE_ENV==="production"?U.exports=ye():U.exports=ke()),U.exports}var r=we();const Ne=n=>n.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),_e=n=>n.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,s,a)=>a?a.toUpperCase():s.toLowerCase()),ce=n=>{const t=_e(n);return t.charAt(0).toUpperCase()+t.slice(1)},ue=(...n)=>n.filter((t,s,a)=>!!t&&t.trim()!==""&&a.indexOf(t)===s).join(" ").trim(),je=n=>{for(const t in n)if(t.startsWith("aria-")||t==="role"||t==="title")return!0};var Ee={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};const Se=o.forwardRef(({color:n="currentColor",size:t=24,strokeWidth:s=2,absoluteStrokeWidth:a,className:c="",children:i,iconNode:d,...p},m)=>o.createElement("svg",{ref:m,...Ee,width:t,height:t,stroke:n,strokeWidth:a?Number(s)*24/Number(t):s,className:ue("lucide",c),...!i&&!je(p)&&{"aria-hidden":"true"},...p},[...d.map(([b,f])=>o.createElement(b,f)),...Array.isArray(i)?i:[i]]));const M=(n,t)=>{const s=o.forwardRef(({className:a,...c},i)=>o.createElement(Se,{ref:i,iconNode:t,className:ue(`lucide-${Ne(ce(n))}`,`lucide-${n}`,a),...c}));return s.displayName=ce(n),s};const Ce=M("external-link",[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]]);const Me=M("user",[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]]),Pe="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2NiZDVlMSI+PHBhdGggZD0iTTEyIDEyYzIuMjEgMCA0LTEuNzkgNC00cy0xLjc5LTQtNC00LTQgMS43OS00IDQgMS43OSA0IDQgNHptMCAyYy0yLjY3IDAtOCAxLjM0LTggNHYyaDE2di0yYzAtMi42Ni01LjMzLTQtOC00eiIvPjwvc3ZnPg==",de=({to:n,className:t,children:s})=>r.jsx("a",{href:n,className:t,children:s}),Re=n=>{const{user:t,LinkComponent:s=de}=n;return r.jsx("div",{className:"w-full",children:t?r.jsxs("div",{className:"aiquants-session-card group relative flex flex-col gap-2 rounded-xl border border-white/20 bg-white/10 p-2.5 shadow-sm backdrop-blur-md transition-all duration-200 hover:border-white/30 hover:bg-white/15 dark:border-slate-700/60 dark:bg-slate-800/60 dark:hover:border-slate-600/80 dark:hover:bg-slate-800/90",children:[r.jsxs("div",{className:"flex min-w-0 items-center gap-2.5",children:[r.jsxs("div",{className:"relative shrink-0",children:[r.jsx("div",{className:"h-8 w-8 overflow-hidden rounded-full border border-white/40 shadow-xs dark:border-slate-500",children:r.jsx("img",{className:"h-full w-full rounded-full object-cover",src:t.photo||Pe,alt:t.displayName||"user profile"})}),r.jsx("span",{className:"absolute -right-0.5 -bottom-0.5 h-2.5 w-2.5 rounded-full border-2 border-slate-900 bg-emerald-400",title:"Online"})]}),r.jsxs("div",{className:"min-w-0 flex-1 leading-tight",children:[r.jsx("div",{className:"truncate font-semibold text-white text-xs tracking-tight dark:text-slate-100",title:t.displayName,children:t.displayName}),r.jsx("div",{className:"mt-0.5 font-medium text-[10px] text-white/75 tracking-tight dark:text-slate-400",children:"Google Account"})]})]}),r.jsxs("div",{className:"grid grid-cols-2 gap-1.5 border-white/15 border-t pt-1.5 dark:border-slate-700/50",children:[r.jsxs(s,{className:"flex items-center justify-center gap-1 rounded-md border border-white/15 bg-white/10 px-2 py-1 font-medium text-[11px] text-white transition-all duration-150 hover:bg-white/25 active:scale-95 dark:border-slate-600/50 dark:bg-slate-700/50 dark:text-slate-200 dark:hover:bg-slate-600/80",to:"/",children:[r.jsx(Me,{size:11,className:"shrink-0 opacity-80"}),r.jsx("span",{className:"truncate",children:"プロフィール"})]}),r.jsxs(s,{className:"flex items-center justify-center gap-1 rounded-md border border-white/15 bg-white/10 px-2 py-1 font-medium text-[11px] text-white transition-all duration-150 hover:bg-white/25 active:scale-95 dark:border-slate-600/50 dark:bg-slate-700/50 dark:text-slate-200 dark:hover:bg-slate-600/80",to:"https://myaccount.google.com/",children:[r.jsx(Ce,{size:11,className:"shrink-0 opacity-80"}),r.jsx("span",{className:"truncate",children:"Google"})]})]})]}):r.jsx("div",{className:"aiquants-session-card flex items-center justify-between rounded-xl border border-white/20 bg-white/10 p-2.5 shadow-xs dark:border-slate-700/60 dark:bg-slate-800/60",children:r.jsx("span",{className:"font-medium text-white/90 text-xs dark:text-slate-200",children:"ログインしてください"})})})},G="aiquants-menu-pin-change";let E={pinned:!1,width:0,active:!1};const Q=(n=240)=>{if(typeof window>"u"||typeof document>"u")return{pinned:!1,width:0,active:!1};try{const t=getComputedStyle(document.documentElement).getPropertyValue("--aiquants-menu-pinned-width").trim();if(t){const d=Number.parseInt(t,10);if(!Number.isNaN(d)){const p=d>0,m=p?d||n:0,b=E.active??p;return E.pinned===p&&E.width===m&&E.active===b||(E={pinned:p,width:m,active:b}),E}}const a=localStorage.getItem("aiquants-menu-pinned")==="true",c=a?n:0,i=E.active??a;return E.pinned===a&&E.width===c&&E.active===i||(E={pinned:a,width:c,active:i}),E}catch{return{pinned:!1,width:0,active:!1}}},X=(n,t,s)=>{if(typeof window>"u")return;const a=s??n,c={pinned:n,width:t,active:a};(E.pinned!==n||E.width!==t||E.active!==a)&&(E=c);const i=new CustomEvent(G,{detail:c,bubbles:!0,cancelable:!1});window.dispatchEvent(i)},fe=(n,t)=>{if(typeof window>"u")return()=>{};const{immediate:s=!0,defaultPinnedWidth:a=240}=t??{};if(s){const i=Q(a);n(i)}const c=i=>{const d=i;d.detail&&n(d.detail)};return window.addEventListener(G,c,{passive:!0}),()=>{window.removeEventListener(G,c)}},Te=n=>{const t=n?.defaultPinnedWidth??240,s=n?.initialPinned??!1,a=o.useCallback(d=>fe(()=>{d()},{immediate:!1,defaultPinnedWidth:t}),[t]),c=o.useCallback(()=>Q(t),[t]),i=o.useCallback(()=>({pinned:s,width:s?t:0}),[s,t]);return o.useSyncExternalStore(a,c,i)};const Oe=M("log-out",[["path",{d:"m16 17 5-5-5-5",key:"1bji2h"}],["path",{d:"M21 12H9",key:"dn1m92"}],["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}]]);const he=M("pin",[["path",{d:"M12 17v5",key:"bb1du9"}],["path",{d:"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z",key:"1nkz8b"}]]);const me=M("pin-off",[["path",{d:"M12 17v5",key:"bb1du9"}],["path",{d:"M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89",key:"znwnzq"}],["path",{d:"m2 2 20 20",key:"1ooewy"}],["path",{d:"M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h11",key:"c9qhm2"}]]);const Ae=M("chart-no-axes-column-increasing",[["path",{d:"M5 21v-6",key:"1hz6c0"}],["path",{d:"M12 21V9",key:"uvy0l4"}],["path",{d:"M19 21V3",key:"11j9sm"}]]);const Ie=M("download",[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]]);const pe=M("file-text",[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]]);const Le=M("link",[["path",{d:"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71",key:"1cjeqo"}],["path",{d:"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71",key:"19qd67"}]]);const ze=M("lock",[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]]);const De=M("table",[["path",{d:"M12 3v18",key:"108xh3"}],["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M3 9h18",key:"1pudct"}],["path",{d:"M3 15h18",key:"5xshup"}]]),Ye=typeof window<"u"?o.useLayoutEffect:o.useEffect,be="aiquants-menu-scroll",xe=new RegExp(/(^https?:\/\/)|(\.(html|htm)?$)/),He={report:pe,slip:pe,table:De,chart:Ae,download:Ie,lock:ze,href:Le},Ve=({mark:n,children:t})=>{const s=n?He[n]:void 0;return s?r.jsxs("div",{className:"flex flex-nowrap items-center",children:[r.jsx(s,{className:"h-3.5 w-3.5 shrink-0"}),r.jsx("div",{className:"aiquants-menu-link mx-1 hover:underline",children:t})]}):r.jsx("span",{className:"mx-1 text-sky-600 hover:underline dark:text-sky-400",children:t})},K=(n,t)=>t?{menu:{id:n.id,title:n.title,href:n.href},submenu:{subid:t.subid,title:t.title,href:t.href,mark:t.mark,new:t.new}}:{menu:{id:n.id,title:n.title,href:n.href}},We=({item:n,parentMenu:t,onMenuSelected:s})=>{if(n.href==="separator")return r.jsx("hr",{className:"aiquants-menu-separator mx-2 my-1 h-px"});const a=r.jsx(Ve,{mark:n.mark,children:n.title}),c={onClick:()=>{s&&s(K(t,n))}};return n.new?r.jsx("a",{href:n.href,rel:"noopener noreferrer",target:"_blank",...c,children:a}):xe.test(n.href)?r.jsx("a",{href:n.href,...c,children:a}):r.jsx(B.Link,{to:n.href,...c,children:a})},ve=n=>n?n.split(/[?#]/)[0].replace(/(?!^\/)\/$/,""):"",ge=(n,t)=>{const s=t!=="/"&&t.endsWith("/")?t.slice(0,-1):t;for(const a of n){if(ve(a.href)===s)return a.id;if(a.submenu){for(const c of a.submenu)if(ve(c.href)===s)return a.id}}return null},Fe=n=>{const{menuList:t,onMenuSelected:s,pinnedSubmenuIds:a=[],onToggleSubmenuPin:c}=n;let i="";try{i=B.useLocation().pathname}catch{typeof window<"u"&&(i=window.location.pathname)}const d=o.useMemo(()=>ge(t,i),[t,i]),[p,m]=o.useState(d),b=o.useRef(i),f=o.useRef(d!==null);o.useEffect(()=>{if(b.current!==i&&(b.current=i,f.current=!1),!f.current){const l=ge(t,i);l!==null&&(m(l),f.current=!0)}},[i,t]);const N=o.useCallback(l=>{a.includes(l)||m(P=>P===l?null:l)},[a]),w=o.useRef(null);Ye(()=>{const l=w.current;if(l)try{const h=sessionStorage.getItem(be);if(h!==null){const P=Number.parseFloat(h);Number.isNaN(P)||(l.scrollTop=P)}}catch{}},[]);const y=o.useCallback(()=>{const l=w.current;if(l)try{sessionStorage.setItem(be,String(l.scrollTop))}catch{}},[]),x=o.useMemo(()=>r.jsx(r.Fragment,{children:t.map(l=>r.jsx("div",{children:l.href?r.jsx("div",{className:"aiquants-menu-list-item relative mb-0.5 ml-1 flex items-center rounded-l-xl px-2.5 py-1 text-xs before:mr-2 before:inline-block before:h-2 before:w-2 before:shrink-0 before:rounded-full before:content-[''] sm:text-sm",children:xe.test(l.href)?r.jsx("a",{href:l.href,onClick:()=>{s&&s(K(l))},children:r.jsx("span",{className:"aiquants-menu-link hover:underline",children:l.title})}):r.jsx(B.Link,{to:l.href,onClick:()=>{s&&s(K(l))},children:r.jsx("span",{className:"aiquants-menu-link hover:underline",children:l.title})})}):r.jsxs("details",{className:"aiquants-menu-accordion-details",open:l.id===p||a.includes(l.id),children:[r.jsxs("summary",{className:"aiquants-menu-list-item aiquants-menu-accordion-summary relative mb-0.5 ml-1 list-none rounded-l-xl px-2.5 py-1 text-xs outline-none before:mr-2 before:inline-block before:h-2 before:w-2 before:shrink-0 before:rounded-full before:content-[''] sm:text-sm",onClick:h=>{h.preventDefault(),N(l.id)},onKeyDown:h=>{(h.key==="Enter"||h.key===" ")&&(h.preventDefault(),N(l.id))},children:[r.jsx("span",{children:l.title}),r.jsx("button",{type:"button",onClick:h=>{h.stopPropagation(),h.preventDefault(),c&&c(l.id)},className:`aiquants-submenu-pin-button ${a.includes(l.id)?"pinned":""}`,title:a.includes(l.id)?"ピン留め解除":"ピン留め",children:a.includes(l.id)?r.jsx(he,{size:13}):r.jsx(me,{size:13})})]}),r.jsx("div",{className:"aiquants-menu-submenu pointer-events-auto my-0.5 mr-1 ml-3.5 rounded-lg px-2 py-1 shadow-sm",children:l.submenu.map(h=>r.jsx("div",{className:"aiquants-menu-accordion-container block w-full whitespace-nowrap py-0.5 text-xs",children:r.jsx(We,{item:h,parentMenu:l,onMenuSelected:s})},h.subid))})]})},l.id))}),[t,s,p,N,a]);return r.jsx("div",{ref:w,onScroll:y,className:"hidden-scrollbar h-0 grow overflow-y-scroll",children:x})},Ue=n=>{const{menuList:t,menuHeader:s,open:a,onMenuSelected:c,onClickSignout:i,theme:d,toggleTheme:p,isPinned:m,onTogglePin:b,pinnedSubmenuIds:f,onToggleSubmenuPin:N}=n;return r.jsxs("div",{className:`aiquants-menu-content fixed top-0 right-0 z-2147483642 flex min-h-dvh w-[240px] select-none flex-col transition-transform duration-500 ${a?"aiquants-menu-translate-x-0":"aiquants-menu-translate-x-250"}`,children:[r.jsx("div",{className:"flex shrink-0 flex-col justify-center border-white/15 border-b px-2.5 py-2 dark:border-slate-700/60",children:s}),r.jsx("div",{className:"flex grow flex-col overflow-y-auto",children:r.jsx(Fe,{menuList:t,onMenuSelected:c,pinnedSubmenuIds:f,onToggleSubmenuPin:N})}),r.jsx("div",{className:"border-white/15 border-t px-2.5 py-1.5 dark:border-slate-700/60",children:r.jsxs("div",{className:"flex items-center justify-between gap-1.5",children:[r.jsx("button",{type:"button",onClick:b,"data-aqmb-pin-button":!0,className:`flex h-7 items-center justify-center rounded-md px-2 text-[11px] text-white shadow-2xs transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-300/60 ${m?"bg-amber-500 hover:bg-amber-600 dark:bg-amber-600 dark:hover:bg-amber-500":"border border-white/20 bg-white/10 hover:bg-white/20 dark:border-slate-600/60 dark:bg-slate-700/60 dark:hover:bg-slate-600"}`,title:m?"ピン留め解除":"ピン留め","aria-label":m?"ピン留め解除":"ピン留め",children:m?r.jsx(he,{size:12}):r.jsx(me,{size:12})}),r.jsx("button",{type:"button",onClick:p,"data-aqmb-theme-button":!0,className:"group relative flex h-7 items-center justify-center rounded-md border border-white/20 bg-white/10 px-2 text-[11px] text-white shadow-2xs backdrop-blur-xs transition-all duration-200 hover:bg-white/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 dark:border-slate-600/60 dark:bg-slate-700/60 dark:hover:bg-slate-600",title:d==="dark"?"ライトモードに切り替え":"ダークモードに切り替え","aria-label":d==="dark"?"ライトモードに切り替え":"ダークモードに切り替え",children:r.jsx("span",{className:"text-xs transition-transform duration-200 group-hover:scale-110",children:d==="dark"?"🌞":"🌙"})}),r.jsxs("button",{type:"button","data-aqmb-signout-button":!0,className:"aiquants-signout-button flex h-7 flex-1 items-center justify-center gap-1.5 whitespace-nowrap rounded-md bg-red-500/90 px-2.5 font-medium text-[11px] text-white shadow-2xs transition-colors duration-200 hover:bg-red-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-300/60 dark:bg-red-600/90 dark:hover:bg-red-500",onClick:i,children:[r.jsx(Oe,{size:11,className:"shrink-0"}),r.jsx("span",{children:"サインアウト"})]})]})})]})},Ge=n=>{const{isOverlay:t,onOverlayClick:s}=n;return r.jsx("button",{type:"button",className:`fixed inset-0 z-2147483640 cursor-default bg-black/50 transition-opacity duration-500 ${t?"opacity-100":"pointer-events-none opacity-0"}`,onClick:s})},Ze=n=>{const{open:t,isOpen:s,onMenuOpen:a,onMenuClose:c,onToggle:i,theme:d="light",className:p}=n,m=t??(s!==void 0?!s:!0),b=o.useRef(m),f=o.useRef(null),N=o.useRef(null),w=o.useRef(null),y=o.useRef(null),x=o.useRef(null),l=o.useCallback(()=>{if(f.current&&N.current&&w.current&&y.current&&x.current){const v=d==="dark"?"#fff":"#000";f.current.style.backgroundColor=v,f.current.style.width="100%",f.current.style.height="3px",f.current.style.transform="none",N.current.style.opacity="1",N.current.style.backgroundColor=v,w.current.style.opacity="1",w.current.style.backgroundColor=v,y.current.style.backgroundColor=v,y.current.style.width="100%",y.current.style.height="3px",y.current.style.transform="none",x.current.style.color=v,x.current.classList.remove("after:content-['close']"),x.current.classList.remove("after:ml-0.5"),x.current.classList.add("after:content-['menu']"),x.current.classList.add("after:-ml-0.5"),b.current=!0}},[d]),h=o.useCallback(()=>{f.current&&N.current&&w.current&&y.current&&x.current&&(f.current.style.backgroundColor="#fff",f.current.style.width="32px",f.current.style.height="4px",f.current.style.transform="translateY(9px) rotate(-45deg)",N.current.style.opacity="0",w.current.style.opacity="0",y.current.style.backgroundColor="#fff",y.current.style.width="32px",y.current.style.height="4px",y.current.style.transform="translateY(-9px) rotate(45deg)",x.current.style.color="#fff",x.current.classList.remove("after:content-['menu']"),x.current.classList.remove("after:-ml-0.5"),x.current.classList.add("after:content-['close']"),x.current.classList.add("after:ml-0.5"),b.current=!1)},[]);o.useEffect(()=>{m?l():h()},[m,l,h]);const P=o.useCallback(()=>{b.current?(h(),a?.(),i?.(!0)):(l(),c?.(),i?.(!1))},[h,l,a,c,i]),I=!m;return r.jsxs("button",{type:"button","data-aqmb-menu-switch":"true","aria-label":I?"Close menu":"Open menu","aria-expanded":I,className:`aiquants-menu-switch z-[2147483647] inline-block h-[27px] w-[27px] cursor-pointer align-middle outline-hidden ${p||""}`,onClick:P,children:[r.jsx("span",{ref:f,className:"absolute top-0 left-0 box-border inline-block h-[3px] w-full select-none transition-all duration-500"}),r.jsx("span",{ref:N,className:"absolute top-[6px] left-0 box-border inline-block h-[3px] w-full select-none transition-all duration-500"}),r.jsx("span",{ref:w,className:"absolute top-[12px] left-0 box-border inline-block h-[3px] w-full select-none transition-all duration-500"}),r.jsx("span",{ref:y,className:"absolute top-[18px] left-0 box-border inline-block h-[3px] w-full select-none transition-all duration-500"}),r.jsx("div",{ref:x,className:"absolute w-full text-xs transition-all duration-500 after:mt-2 after:block"})]})},$=typeof window<"u"?o.useLayoutEffect:o.useEffect,Je=n=>{const{menuList:t,menuHeader:s,onClickSignout:a,isMenuhide:c,isMenuHide:i,theme:d,toggleTheme:p,onMenuNavigate:m,isPinned:b,pinnedWidth:f=240,onPinChange:N,pinnedSubmenuIds:w,initialPinnedSubmenuIds:y,onSubmenuPinChange:x,closeOnEscape:l="auto"}=n,h=i??c??!1,[P,I]=o.useState(()=>{try{return localStorage.getItem("aiquants-menu-pinned")==="true"}catch{return!1}}),v=b!==void 0?b:P,[R,L]=o.useState(v);o.useEffect(()=>{v&&L(!0)},[v]);const[H,ee]=o.useState(()=>{if(y)return y;try{const k=localStorage.getItem("aiquants-submenu-pinned");if(k){const C=JSON.parse(k);if(Array.isArray(C))return C.filter(T=>typeof T=="number")}}catch{}return[]}),te=w!==void 0?w:H,V=o.useCallback(k=>{const C=w!==void 0?w:H,T=C.includes(k)?C.filter(J=>J!==k):[...C,k];if(w===void 0){ee(T);try{localStorage.setItem("aiquants-submenu-pinned",JSON.stringify(T))}catch{}}x&&x(T)},[w,H,x]),W=o.useRef(N);$(()=>{W.current=N},[N]),$(()=>{const k=v?f:0,C=`${k}px`;document.documentElement.style.setProperty("--aiquants-menu-pinned-width",C),X(v,k,R||v)},[v,f,R]),$(()=>()=>{document.documentElement.style.setProperty("--aiquants-menu-pinned-width","0px"),X(!1,0)},[]);const ne=o.useCallback(()=>{L(!0)},[]),O=o.useCallback(()=>{if(L(!1),b===void 0){I(!1);try{localStorage.removeItem("aiquants-menu-pinned")}catch{}}W.current?.(!1,0)},[b]),Z=o.useCallback(()=>{const k=!v,C=k?f:0;if(b===void 0){I(k);try{k?localStorage.setItem("aiquants-menu-pinned","true"):localStorage.removeItem("aiquants-menu-pinned")}catch{}}W.current?.(k,C)},[v,b,f]),re=o.useCallback(k=>{m&&m(k),v||L(!1)},[m,v]),A=o.useCallback(k=>{k.key==="Escape"&&O()},[O]),F=l===!0||l==="auto"&&!v;return o.useEffect(()=>(R&&F?window.addEventListener("keydown",A):window.removeEventListener("keydown",A),()=>{window.removeEventListener("keydown",A)}),[R,F,A]),h?null:r.jsxs("div",{className:`aiquants-menu-bar ${d}`,children:[r.jsx(Ze,{onMenuClose:O,onMenuOpen:ne,open:!R,theme:d}),r.jsx(Ue,{menuList:t,menuHeader:s,onClickSignout:a,onMenuSelected:re,open:R,theme:d,toggleTheme:p,isPinned:v,onTogglePin:Z,pinnedSubmenuIds:te,onToggleSubmenuPin:V}),r.jsx(Ge,{isOverlay:R&&!v,onOverlayClick:O})]})};S.DefaultLink=de,S.MENU_PIN_CHANGE_EVENT=G,S.MenuBar=Je,S.SessionInfo=Re,S.dispatchMenuPinChange=X,S.getInitialPinState=Q,S.subscribeMenuPinChange=fe,S.useMenuPinState=Te,Object.defineProperty(S,Symbol.toStringTag,{value:"Module"})}));
|
package/dist/types/user.d.ts
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module types
|
|
3
|
-
* @description Common type definitions for @aiquants/menu-bar.
|
|
4
|
-
* @description @aiquants/menu-bar の共通型定義。
|
|
5
|
-
*/
|
|
6
1
|
export type Theme = "light" | "dark";
|
|
7
|
-
/**
|
|
8
|
-
* Menu pin change event payload detail interface.
|
|
9
|
-
* メニューピン留め状態変更イベントの詳細ペイロード。
|
|
10
|
-
*/
|
|
11
2
|
export interface MenuPinChangeDetail {
|
|
12
|
-
/** Whether the menu is currently pinned open. メニューが現在ピン留めされているかどうか。 */
|
|
13
3
|
pinned: boolean;
|
|
14
|
-
/** Pinned width in pixels (e.g. 240 or 0). ピン留め時の幅 (ピクセル単位)。 */
|
|
15
4
|
width: number;
|
|
5
|
+
active?: boolean;
|
|
16
6
|
}
|
|
17
|
-
/**
|
|
18
|
-
* Custom Event type for menu pin change events.
|
|
19
|
-
* メニューピン留め状態変更カスタムイベントの型。
|
|
20
|
-
*/
|
|
21
7
|
export type MenuPinCustomEvent = CustomEvent<MenuPinChangeDetail>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiquants/menu-bar",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A React menu bar component with authentication support and theming",
|
|
6
6
|
"keywords": [
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
},
|
|
33
33
|
"files": [
|
|
34
34
|
"dist",
|
|
35
|
-
"src",
|
|
36
35
|
"README.md",
|
|
37
36
|
"LICENSE"
|
|
38
37
|
],
|
|
@@ -70,7 +69,7 @@
|
|
|
70
69
|
"access": "public"
|
|
71
70
|
},
|
|
72
71
|
"scripts": {
|
|
73
|
-
"build": "vite build && pnpm build:css",
|
|
72
|
+
"build": "vite build && pnpm build:css && node ../../.config/scripts/strip-dts-comments.mjs dist",
|
|
74
73
|
"build:css": "tailwindcss -i src/styles/components.entry.css -o dist/styles/menu-bar.css --minify && tailwindcss -i src/styles/standalone.entry.css -o dist/styles/menu-bar.standalone.css --minify",
|
|
75
74
|
"dev": "vite build --watch",
|
|
76
75
|
"watch": "vite build --watch",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/src/MenuBar.tsx
DELETED
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module MenuBar
|
|
3
|
-
* @description Main menu bar component for @aiquants/menu-bar.
|
|
4
|
-
* @description @aiquants/menu-bar のメインメニューバーコンポーネント。
|
|
5
|
-
*/
|
|
6
|
-
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react"
|
|
7
|
-
|
|
8
|
-
const useSafeLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect
|
|
9
|
-
|
|
10
|
-
import { MenuContent } from "./contents/MenuContent"
|
|
11
|
-
import type { IMenu, MenuNavigationPayload } from "./contents/MenuList"
|
|
12
|
-
import { OverlayShadow } from "./contents/OverlayShadow"
|
|
13
|
-
import { MenuSwitch } from "./elements/MenuSwitch"
|
|
14
|
-
import { dispatchMenuPinChange } from "./events/pinEvent"
|
|
15
|
-
import type { Theme } from "./types"
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Props interface for the MenuBar component.
|
|
19
|
-
* MenuBar コンポーネントのプロップスインターフェース。
|
|
20
|
-
*/
|
|
21
|
-
export interface IMenuBarProps {
|
|
22
|
-
/** List of menu items. メニュー項目のリスト。 */
|
|
23
|
-
menuList: IMenu[]
|
|
24
|
-
/** Optional header content rendered at top of menu drawer. メニューヘッダー要素。 */
|
|
25
|
-
menuHeader?: React.ReactNode
|
|
26
|
-
/** Callback handler for sign out button click. サインアウト処理ハンドラー。 */
|
|
27
|
-
onClickSignout(): void
|
|
28
|
-
/** Whether to hide the menu bar (legacy camelCase). メニュー非表示フラグ(旧表記)。 */
|
|
29
|
-
isMenuhide?: boolean
|
|
30
|
-
/** Whether to hide the menu bar. メニュー非表示フラグ。 */
|
|
31
|
-
isMenuHide?: boolean
|
|
32
|
-
/** Current active color theme. 現在のテーマ。 */
|
|
33
|
-
theme: Theme
|
|
34
|
-
/** Toggle handler for switching color theme. テーマ切り替えハンドラー。 */
|
|
35
|
-
toggleTheme: () => void
|
|
36
|
-
/** Navigation callback when a menu item is selected. メニュー遷移ハンドラー。 */
|
|
37
|
-
onMenuNavigate?(payload: MenuNavigationPayload): void
|
|
38
|
-
/** Controlled pinning state (optional). ピン留め状態制御プロップ。 */
|
|
39
|
-
isPinned?: boolean
|
|
40
|
-
/** Custom width in pixels when menu is pinned (default: 240). ピン留め時の幅(px)。 */
|
|
41
|
-
pinnedWidth?: number
|
|
42
|
-
/** Callback invoked when menu pin state changes. ピン留め状態変更時のコールバック。 */
|
|
43
|
-
onPinChange?(pinned: boolean, widthPx: number): void
|
|
44
|
-
/** Controlled list of pinned submenu IDs. ピン留めサブメニューIDリスト(制御)。 */
|
|
45
|
-
pinnedSubmenuIds?: number[]
|
|
46
|
-
/** Initial list of pinned submenu IDs for uncontrolled mode. ピン留めサブメニューID初期リスト。 */
|
|
47
|
-
initialPinnedSubmenuIds?: number[]
|
|
48
|
-
/** Callback invoked when submenu pin state changes. サブメニューピン留め変更時コールバック。 */
|
|
49
|
-
onSubmenuPinChange?(pinnedIds: number[]): void
|
|
50
|
-
/** Controls whether the Escape key closes the menu drawer. Escape キーによるメニュー閉鎖制御。 */
|
|
51
|
-
closeOnEscape?: boolean | "auto"
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Renders the primary collapsible and pinnable menu bar with drawer navigation.
|
|
56
|
-
* 折りたたみ・ピン留め対応のプライマリメニューバーコンポーネント。
|
|
57
|
-
*
|
|
58
|
-
* @param props - MenuBarProps configuration.
|
|
59
|
-
* @returns Rendered JSX element or null.
|
|
60
|
-
*/
|
|
61
|
-
export const MenuBar = (props: IMenuBarProps): React.JSX.Element | null => {
|
|
62
|
-
const {
|
|
63
|
-
menuList,
|
|
64
|
-
menuHeader,
|
|
65
|
-
onClickSignout,
|
|
66
|
-
isMenuhide,
|
|
67
|
-
isMenuHide,
|
|
68
|
-
theme,
|
|
69
|
-
toggleTheme,
|
|
70
|
-
onMenuNavigate,
|
|
71
|
-
isPinned: propIsPinned,
|
|
72
|
-
pinnedWidth = 240,
|
|
73
|
-
onPinChange,
|
|
74
|
-
pinnedSubmenuIds: propPinnedSubmenuIds,
|
|
75
|
-
initialPinnedSubmenuIds,
|
|
76
|
-
onSubmenuPinChange,
|
|
77
|
-
closeOnEscape = "auto",
|
|
78
|
-
} = props
|
|
79
|
-
|
|
80
|
-
const shouldHideMenu = isMenuHide ?? isMenuhide ?? false
|
|
81
|
-
|
|
82
|
-
const [internalIsPinned, setInternalIsPinned] = useState(() => {
|
|
83
|
-
try {
|
|
84
|
-
return localStorage.getItem("aiquants-menu-pinned") === "true"
|
|
85
|
-
} catch {
|
|
86
|
-
return false
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
const isPinned = propIsPinned !== undefined ? propIsPinned : internalIsPinned
|
|
91
|
-
const [isMenuOpen, setIsMenuOpen] = useState(isPinned)
|
|
92
|
-
|
|
93
|
-
// isPinned が true に変化した場合は自動的にメニューを開いた状態にする
|
|
94
|
-
useEffect(() => {
|
|
95
|
-
if (isPinned) {
|
|
96
|
-
setIsMenuOpen(true)
|
|
97
|
-
}
|
|
98
|
-
}, [isPinned])
|
|
99
|
-
|
|
100
|
-
const [pinnedSubmenuIds, setPinnedSubmenuIds] = useState<number[]>(() => {
|
|
101
|
-
if (initialPinnedSubmenuIds) {
|
|
102
|
-
return initialPinnedSubmenuIds
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
const saved = localStorage.getItem("aiquants-submenu-pinned")
|
|
106
|
-
if (saved) {
|
|
107
|
-
const parsed = JSON.parse(saved)
|
|
108
|
-
if (Array.isArray(parsed)) {
|
|
109
|
-
return parsed.filter((id) => typeof id === "number")
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
} catch {}
|
|
113
|
-
return []
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
const activePinnedSubmenuIds = propPinnedSubmenuIds !== undefined ? propPinnedSubmenuIds : pinnedSubmenuIds
|
|
117
|
-
|
|
118
|
-
const handleToggleSubmenuPin = useCallback(
|
|
119
|
-
(id: number) => {
|
|
120
|
-
const currentIds = propPinnedSubmenuIds !== undefined ? propPinnedSubmenuIds : pinnedSubmenuIds
|
|
121
|
-
const nextIds = currentIds.includes(id) ? currentIds.filter((x) => x !== id) : [...currentIds, id]
|
|
122
|
-
|
|
123
|
-
if (propPinnedSubmenuIds === undefined) {
|
|
124
|
-
setPinnedSubmenuIds(nextIds)
|
|
125
|
-
try {
|
|
126
|
-
localStorage.setItem("aiquants-submenu-pinned", JSON.stringify(nextIds))
|
|
127
|
-
} catch {}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (onSubmenuPinChange) {
|
|
131
|
-
onSubmenuPinChange(nextIds)
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
[propPinnedSubmenuIds, pinnedSubmenuIds, onSubmenuPinChange],
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
// コールバック関数参照を useRef で最新保持し、エフェクト再実行のインライン関数連鎖を遮断
|
|
138
|
-
const onPinChangeRef = useRef(onPinChange)
|
|
139
|
-
useSafeLayoutEffect(() => {
|
|
140
|
-
onPinChangeRef.current = onPinChange
|
|
141
|
-
}, [onPinChange])
|
|
142
|
-
|
|
143
|
-
// ピン状態変化時に CSS 変数をセットし、CustomEvent を自動発行
|
|
144
|
-
useSafeLayoutEffect(() => {
|
|
145
|
-
const effectiveWidth = isPinned ? pinnedWidth : 0
|
|
146
|
-
const widthCss = `${effectiveWidth}px`
|
|
147
|
-
document.documentElement.style.setProperty("--aiquants-menu-pinned-width", widthCss)
|
|
148
|
-
|
|
149
|
-
// CustomEvent 発行
|
|
150
|
-
dispatchMenuPinChange(isPinned, effectiveWidth)
|
|
151
|
-
}, [isPinned, pinnedWidth])
|
|
152
|
-
|
|
153
|
-
// アンマウント時に CSS 変数をリセットしピン解除通知を発行
|
|
154
|
-
useSafeLayoutEffect(() => {
|
|
155
|
-
return () => {
|
|
156
|
-
document.documentElement.style.setProperty("--aiquants-menu-pinned-width", "0px")
|
|
157
|
-
dispatchMenuPinChange(false, 0)
|
|
158
|
-
}
|
|
159
|
-
}, [])
|
|
160
|
-
|
|
161
|
-
const handleMenuOpen = useCallback(() => {
|
|
162
|
-
setIsMenuOpen(true)
|
|
163
|
-
}, [])
|
|
164
|
-
|
|
165
|
-
const handleMenuClose = useCallback(() => {
|
|
166
|
-
setIsMenuOpen(false)
|
|
167
|
-
if (propIsPinned === undefined) {
|
|
168
|
-
setInternalIsPinned(false)
|
|
169
|
-
try {
|
|
170
|
-
localStorage.removeItem("aiquants-menu-pinned")
|
|
171
|
-
} catch {}
|
|
172
|
-
}
|
|
173
|
-
onPinChangeRef.current?.(false, 0)
|
|
174
|
-
}, [propIsPinned])
|
|
175
|
-
|
|
176
|
-
const handleTogglePin = useCallback(() => {
|
|
177
|
-
const nextPinned = !isPinned
|
|
178
|
-
const nextWidth = nextPinned ? pinnedWidth : 0
|
|
179
|
-
|
|
180
|
-
if (propIsPinned === undefined) {
|
|
181
|
-
setInternalIsPinned(nextPinned)
|
|
182
|
-
try {
|
|
183
|
-
if (nextPinned) {
|
|
184
|
-
localStorage.setItem("aiquants-menu-pinned", "true")
|
|
185
|
-
} else {
|
|
186
|
-
localStorage.removeItem("aiquants-menu-pinned")
|
|
187
|
-
}
|
|
188
|
-
} catch {}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
onPinChangeRef.current?.(nextPinned, nextWidth)
|
|
192
|
-
}, [isPinned, propIsPinned, pinnedWidth])
|
|
193
|
-
|
|
194
|
-
const handleMenuSelected = useCallback(
|
|
195
|
-
(payload: MenuNavigationPayload) => {
|
|
196
|
-
if (onMenuNavigate) {
|
|
197
|
-
onMenuNavigate(payload)
|
|
198
|
-
}
|
|
199
|
-
if (!isPinned) {
|
|
200
|
-
setIsMenuOpen(false)
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
[onMenuNavigate, isPinned],
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
const handleEscKey = useCallback(
|
|
207
|
-
(e: KeyboardEvent) => {
|
|
208
|
-
if (e.key === "Escape") {
|
|
209
|
-
handleMenuClose()
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
[handleMenuClose],
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
const escapeCloses = closeOnEscape === true || (closeOnEscape === "auto" && !isPinned)
|
|
216
|
-
|
|
217
|
-
useEffect(() => {
|
|
218
|
-
if (isMenuOpen && escapeCloses) {
|
|
219
|
-
window.addEventListener("keydown", handleEscKey)
|
|
220
|
-
} else {
|
|
221
|
-
window.removeEventListener("keydown", handleEscKey)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return () => {
|
|
225
|
-
window.removeEventListener("keydown", handleEscKey)
|
|
226
|
-
}
|
|
227
|
-
}, [isMenuOpen, escapeCloses, handleEscKey])
|
|
228
|
-
|
|
229
|
-
return shouldHideMenu ? null : (
|
|
230
|
-
<div className={`aiquants-menu-bar ${theme}`}>
|
|
231
|
-
<MenuSwitch onMenuClose={handleMenuClose} onMenuOpen={handleMenuOpen} open={!isMenuOpen} theme={theme} />
|
|
232
|
-
<MenuContent
|
|
233
|
-
menuList={menuList}
|
|
234
|
-
menuHeader={menuHeader}
|
|
235
|
-
onClickSignout={onClickSignout}
|
|
236
|
-
onMenuSelected={handleMenuSelected}
|
|
237
|
-
open={isMenuOpen}
|
|
238
|
-
theme={theme}
|
|
239
|
-
toggleTheme={toggleTheme}
|
|
240
|
-
isPinned={isPinned}
|
|
241
|
-
onTogglePin={handleTogglePin}
|
|
242
|
-
pinnedSubmenuIds={activePinnedSubmenuIds}
|
|
243
|
-
onToggleSubmenuPin={handleToggleSubmenuPin}
|
|
244
|
-
/>
|
|
245
|
-
<OverlayShadow isOverlay={isMenuOpen && !isPinned} onOverlayClick={handleMenuClose} />
|
|
246
|
-
</div>
|
|
247
|
-
)
|
|
248
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { act, render, renderHook } from "@testing-library/react"
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
|
|
3
|
-
import { dispatchMenuPinChange, getInitialPinState, subscribeMenuPinChange } from "../events/pinEvent"
|
|
4
|
-
import { useMenuPinState } from "../hooks/useMenuPinState"
|
|
5
|
-
import { MenuBar } from "../MenuBar"
|
|
6
|
-
|
|
7
|
-
describe("pinEvent module & useMenuPinState hook", () => {
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
localStorage.clear()
|
|
10
|
-
document.documentElement.style.removeProperty("--aiquants-menu-pinned-width")
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
vi.restoreAllMocks()
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it("getInitialPinState reads document style or localStorage safely", () => {
|
|
18
|
-
expect(getInitialPinState(240)).toEqual({ pinned: false, width: 0 })
|
|
19
|
-
|
|
20
|
-
localStorage.setItem("aiquants-menu-pinned", "true")
|
|
21
|
-
expect(getInitialPinState(240)).toEqual({ pinned: true, width: 240 })
|
|
22
|
-
|
|
23
|
-
document.documentElement.style.setProperty("--aiquants-menu-pinned-width", "280px")
|
|
24
|
-
expect(getInitialPinState(240)).toEqual({ pinned: true, width: 280 })
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it("subscribeMenuPinChange fires immediately when immediate: true", () => {
|
|
28
|
-
localStorage.setItem("aiquants-menu-pinned", "true")
|
|
29
|
-
const listener = vi.fn()
|
|
30
|
-
|
|
31
|
-
const unsubscribe = subscribeMenuPinChange(listener, { immediate: true })
|
|
32
|
-
expect(listener).toHaveBeenCalledWith({ pinned: true, width: 240 })
|
|
33
|
-
|
|
34
|
-
dispatchMenuPinChange(false, 0)
|
|
35
|
-
expect(listener).toHaveBeenCalledWith({ pinned: false, width: 0 })
|
|
36
|
-
|
|
37
|
-
unsubscribe()
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it("useMenuPinState hook syncs state correctly and avoids hydration mismatch", () => {
|
|
41
|
-
localStorage.setItem("aiquants-menu-pinned", "true")
|
|
42
|
-
const { result } = renderHook(() => useMenuPinState({ defaultPinnedWidth: 240 }))
|
|
43
|
-
|
|
44
|
-
expect(result.current).toEqual({ pinned: true, width: 240 })
|
|
45
|
-
|
|
46
|
-
act(() => {
|
|
47
|
-
dispatchMenuPinChange(false, 0)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
expect(result.current).toEqual({ pinned: false, width: 0 })
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it("MenuBar triggers onPinChange on toggle and dispatches CustomEvent", () => {
|
|
54
|
-
const onPinChange = vi.fn()
|
|
55
|
-
const eventListener = vi.fn()
|
|
56
|
-
const unsubscribe = subscribeMenuPinChange(eventListener, { immediate: false })
|
|
57
|
-
|
|
58
|
-
const { unmount } = render(<MenuBar menuList={[]} onClickSignout={() => {}} theme="light" toggleTheme={() => {}} isPinned={true} pinnedWidth={240} onPinChange={onPinChange} />)
|
|
59
|
-
|
|
60
|
-
expect(eventListener).toHaveBeenCalledWith({ pinned: true, width: 240 })
|
|
61
|
-
expect(document.documentElement.style.getPropertyValue("--aiquants-menu-pinned-width")).toBe("240px")
|
|
62
|
-
|
|
63
|
-
unmount()
|
|
64
|
-
expect(document.documentElement.style.getPropertyValue("--aiquants-menu-pinned-width")).toBe("0px")
|
|
65
|
-
|
|
66
|
-
unsubscribe()
|
|
67
|
-
})
|
|
68
|
-
})
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import ExternalLink from "lucide-react/dist/esm/icons/external-link.js"
|
|
2
|
-
import User from "lucide-react/dist/esm/icons/user.js"
|
|
3
|
-
import type { UserProfile } from "../types/user"
|
|
4
|
-
|
|
5
|
-
const DEFAULT_USER_ICON =
|
|
6
|
-
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2NiZDVlMSI+PHBhdGggZD0iTTEyIDEyYzIuMjEgMCA0LTEuNzkgNC00cy0xLjc5LTQtNC00LTQgMS43OS00IDQgMS43OSA0IDQgNHptMCAyYy0yLjY3IDAtOCAxLjM0LTggNHYyaDE2di0yYzAtMi42Ni01LjMzLTQtOC00eiIvPjwvc3ZnPg=="
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Link component props interface.
|
|
10
|
-
* リンクコンポーネントのプロパティ。
|
|
11
|
-
*/
|
|
12
|
-
export interface LinkProps {
|
|
13
|
-
/** Link destination URL */
|
|
14
|
-
to: string
|
|
15
|
-
/** CSS class name */
|
|
16
|
-
className?: string
|
|
17
|
-
/** Link content */
|
|
18
|
-
children: React.ReactNode
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Generic Link component that can be replaced with router-specific implementation.
|
|
23
|
-
* ルーター固有の実装で置き換え可能な汎用リンクコンポーネント。
|
|
24
|
-
*/
|
|
25
|
-
export const DefaultLink = ({ to, className, children }: LinkProps): React.JSX.Element => (
|
|
26
|
-
<a href={to} className={className}>
|
|
27
|
-
{children}
|
|
28
|
-
</a>
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* SessionInfo component props interface.
|
|
33
|
-
* ユーザーセッション情報を表示するコンポーネントのプロパティ。
|
|
34
|
-
*/
|
|
35
|
-
export interface SessionInfoProps {
|
|
36
|
-
/** User profile information from Google OAuth */
|
|
37
|
-
user: UserProfile | null
|
|
38
|
-
/** Custom Link component (optional, defaults to DefaultLink) */
|
|
39
|
-
LinkComponent?: React.ComponentType<LinkProps>
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* SessionInfo component for displaying user session information.
|
|
44
|
-
* Displays user profile photo, navigation links, and user name when authenticated.
|
|
45
|
-
*
|
|
46
|
-
* ユーザーセッション情報を表示するコンポーネント。
|
|
47
|
-
* 認証時にプロフィール写真、ナビゲーションリンク、ユーザー名を表示する。
|
|
48
|
-
*/
|
|
49
|
-
export const SessionInfo = (props: SessionInfoProps): React.JSX.Element => {
|
|
50
|
-
const { user, LinkComponent = DefaultLink } = props
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
<div className="w-full">
|
|
54
|
-
{user ? (
|
|
55
|
-
<div className="aiquants-session-card group relative flex flex-col gap-2 rounded-xl border border-white/20 bg-white/10 p-2.5 shadow-sm backdrop-blur-md transition-all duration-200 hover:border-white/30 hover:bg-white/15 dark:border-slate-700/60 dark:bg-slate-800/60 dark:hover:border-slate-600/80 dark:hover:bg-slate-800/90">
|
|
56
|
-
{/* アバター & ユーザー名 */}
|
|
57
|
-
<div className="flex min-w-0 items-center gap-2.5">
|
|
58
|
-
<div className="relative shrink-0">
|
|
59
|
-
<div className="h-8 w-8 overflow-hidden rounded-full border border-white/40 shadow-xs dark:border-slate-500">
|
|
60
|
-
<img className="h-full w-full rounded-full object-cover" src={user.photo || DEFAULT_USER_ICON} alt={user.displayName || "user profile"} />
|
|
61
|
-
</div>
|
|
62
|
-
<span className="absolute -right-0.5 -bottom-0.5 h-2.5 w-2.5 rounded-full border-2 border-slate-900 bg-emerald-400" title="Online" />
|
|
63
|
-
</div>
|
|
64
|
-
<div className="min-w-0 flex-1 leading-tight">
|
|
65
|
-
<div className="truncate font-semibold text-white text-xs tracking-tight dark:text-slate-100" title={user.displayName}>
|
|
66
|
-
{user.displayName}
|
|
67
|
-
</div>
|
|
68
|
-
<div className="mt-0.5 font-medium text-[10px] text-white/75 tracking-tight dark:text-slate-400">Google Account</div>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
|
|
72
|
-
{/* アクションボタン */}
|
|
73
|
-
<div className="grid grid-cols-2 gap-1.5 border-white/15 border-t pt-1.5 dark:border-slate-700/50">
|
|
74
|
-
<LinkComponent
|
|
75
|
-
className="flex items-center justify-center gap-1 rounded-md border border-white/15 bg-white/10 px-2 py-1 font-medium text-[11px] text-white transition-all duration-150 hover:bg-white/25 active:scale-95 dark:border-slate-600/50 dark:bg-slate-700/50 dark:text-slate-200 dark:hover:bg-slate-600/80"
|
|
76
|
-
to="/">
|
|
77
|
-
<User size={11} className="shrink-0 opacity-80" />
|
|
78
|
-
<span className="truncate">プロフィール</span>
|
|
79
|
-
</LinkComponent>
|
|
80
|
-
<LinkComponent
|
|
81
|
-
className="flex items-center justify-center gap-1 rounded-md border border-white/15 bg-white/10 px-2 py-1 font-medium text-[11px] text-white transition-all duration-150 hover:bg-white/25 active:scale-95 dark:border-slate-600/50 dark:bg-slate-700/50 dark:text-slate-200 dark:hover:bg-slate-600/80"
|
|
82
|
-
to="https://myaccount.google.com/">
|
|
83
|
-
<ExternalLink size={11} className="shrink-0 opacity-80" />
|
|
84
|
-
<span className="truncate">Google</span>
|
|
85
|
-
</LinkComponent>
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
|
-
) : (
|
|
89
|
-
<div className="aiquants-session-card flex items-center justify-between rounded-xl border border-white/20 bg-white/10 p-2.5 shadow-xs dark:border-slate-700/60 dark:bg-slate-800/60">
|
|
90
|
-
<span className="font-medium text-white/90 text-xs dark:text-slate-200">ログインしてください</span>
|
|
91
|
-
</div>
|
|
92
|
-
)}
|
|
93
|
-
</div>
|
|
94
|
-
)
|
|
95
|
-
}
|