@wildo-ai/presets-components 1.1.5 → 1.1.7
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/esm/.native.tsbuildinfo +1 -0
- package/dist/esm/components/actions/action-bar.d.ts.map +1 -1
- package/dist/esm/components/actions/action-bar.js +5 -2
- package/dist/esm/components/actions/action-bar.js.map +1 -1
- package/dist/esm/components/ai-elements/chat/suggestion.d.ts.map +1 -1
- package/dist/esm/components/ai-elements/chat/suggestion.js +8 -1
- package/dist/esm/components/ai-elements/chat/suggestion.js.map +1 -1
- package/dist/esm/components/ai-elements/decision/approval.d.ts +108 -13
- package/dist/esm/components/ai-elements/decision/approval.d.ts.map +1 -1
- package/dist/esm/components/ai-elements/decision/approval.js +60 -10
- package/dist/esm/components/ai-elements/decision/approval.js.map +1 -1
- package/dist/esm/components/ai-elements/graph/graph-runtime.d.ts +3 -1
- package/dist/esm/components/ai-elements/graph/graph-runtime.d.ts.map +1 -1
- package/dist/esm/components/ai-elements/graph/graph-runtime.js +3 -1
- package/dist/esm/components/ai-elements/graph/graph-runtime.js.map +1 -1
- package/dist/esm/components/app/app-layout-main-container.d.ts +9 -0
- package/dist/esm/components/app/app-layout-main-container.d.ts.map +1 -1
- package/dist/esm/components/app/app-layout-main-container.js +17 -23
- package/dist/esm/components/app/app-layout-main-container.js.map +1 -1
- package/dist/esm/components/app/app-layout-main-container.labels.d.ts.map +1 -1
- package/dist/esm/components/app/app-layout-main-container.labels.js +27 -0
- package/dist/esm/components/app/app-layout-main-container.labels.js.map +1 -1
- package/dist/esm/components/billing/billing-plan-change-preview.d.ts.map +1 -1
- package/dist/esm/components/billing/billing-plan-change-preview.js +5 -2
- package/dist/esm/components/billing/billing-plan-change-preview.js.map +1 -1
- package/dist/esm/components/billing/billing-plan-change-preview.labels.d.ts.map +1 -1
- package/dist/esm/components/billing/billing-plan-change-preview.labels.js +3 -0
- package/dist/esm/components/billing/billing-plan-change-preview.labels.js.map +1 -1
- package/dist/esm/components/billing/billing-pricing-table.d.ts +1 -1
- package/dist/esm/components/billing/billing-pricing-table.d.ts.map +1 -1
- package/dist/esm/components/billing/billing-pricing-table.js +8 -4
- package/dist/esm/components/billing/billing-pricing-table.js.map +1 -1
- package/dist/esm/components/billing/billing-pricing-table.labels.d.ts.map +1 -1
- package/dist/esm/components/billing/billing-pricing-table.labels.js +7 -1
- package/dist/esm/components/billing/billing-pricing-table.labels.js.map +1 -1
- package/dist/esm/components/billing/billing-usage-dashboard.d.ts.map +1 -1
- package/dist/esm/components/billing/billing-usage-dashboard.js +6 -3
- package/dist/esm/components/billing/billing-usage-dashboard.js.map +1 -1
- package/dist/esm/components/billing/billing-usage-dashboard.labels.d.ts.map +1 -1
- package/dist/esm/components/billing/billing-usage-dashboard.labels.js +2 -1
- package/dist/esm/components/billing/billing-usage-dashboard.labels.js.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-enum.d.ts.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-enum.js +18 -4
- package/dist/esm/components/data-display/formatters/display-field-enum.js.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-file.d.ts.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-file.js +13 -14
- package/dist/esm/components/data-display/formatters/display-field-file.js.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-file.labels.d.ts.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-file.labels.js +1 -0
- package/dist/esm/components/data-display/formatters/display-field-file.labels.js.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-number.d.ts.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-number.js +6 -1
- package/dist/esm/components/data-display/formatters/display-field-number.js.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-number.labels.d.ts.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-number.labels.js +5 -2
- package/dist/esm/components/data-display/formatters/display-field-number.labels.js.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-string.d.ts +1 -1
- package/dist/esm/components/data-display/formatters/display-field-string.d.ts.map +1 -1
- package/dist/esm/components/data-display/formatters/display-field-string.js +51 -12
- package/dist/esm/components/data-display/formatters/display-field-string.js.map +1 -1
- package/dist/esm/components/data-display/untrusted-html-content.d.ts +55 -0
- package/dist/esm/components/data-display/untrusted-html-content.d.ts.map +1 -0
- package/dist/esm/components/data-display/untrusted-html-content.js +67 -0
- package/dist/esm/components/data-display/untrusted-html-content.js.map +1 -0
- package/dist/esm/components/form/chromes/form-primitive.labels.d.ts.map +1 -1
- package/dist/esm/components/form/chromes/form-primitive.labels.js +9 -0
- package/dist/esm/components/form/chromes/form-primitive.labels.js.map +1 -1
- package/dist/esm/components/form/combobox.d.ts.map +1 -1
- package/dist/esm/components/form/combobox.js +10 -10
- package/dist/esm/components/form/combobox.js.map +1 -1
- package/dist/esm/components/form/controls/address/providers/google-places-address-lookup.adapter.d.ts +42 -0
- package/dist/esm/components/form/controls/address/providers/google-places-address-lookup.adapter.d.ts.map +1 -0
- package/dist/esm/components/form/controls/address/providers/google-places-address-lookup.adapter.js +120 -0
- package/dist/esm/components/form/controls/address/providers/google-places-address-lookup.adapter.js.map +1 -0
- package/dist/esm/components/form/controls/address/providers/google-places-address-lookup.d.ts +16 -0
- package/dist/esm/components/form/controls/address/providers/google-places-address-lookup.d.ts.map +1 -0
- package/dist/esm/components/form/controls/address/providers/google-places-address-lookup.js +8 -0
- package/dist/esm/components/form/controls/address/providers/google-places-address-lookup.js.map +1 -0
- package/dist/esm/components/navigation/app-level/activity-bar.d.ts.map +1 -1
- package/dist/esm/components/navigation/app-level/activity-bar.js +2 -2
- package/dist/esm/components/navigation/app-level/activity-bar.js.map +1 -1
- package/dist/esm/components/navigation/app-level/menu-user-org.d.ts.map +1 -1
- package/dist/esm/components/navigation/app-level/menu-user-org.js +10 -4
- package/dist/esm/components/navigation/app-level/menu-user-org.js.map +1 -1
- package/dist/esm/components/navigation/app-level/menu-user-org.labels.d.ts.map +1 -1
- package/dist/esm/components/navigation/app-level/menu-user-org.labels.js +7 -0
- package/dist/esm/components/navigation/app-level/menu-user-org.labels.js.map +1 -1
- package/dist/esm/components/navigation/app-level/menubar.d.ts.map +1 -1
- package/dist/esm/components/navigation/app-level/menubar.js +6 -6
- package/dist/esm/components/navigation/app-level/menubar.js.map +1 -1
- package/dist/esm/components/navigation/app-level/navigation-back.d.ts.map +1 -1
- package/dist/esm/components/navigation/app-level/navigation-back.js +27 -9
- package/dist/esm/components/navigation/app-level/navigation-back.js.map +1 -1
- package/dist/esm/components/navigation/app-level/sidebar.js +3 -3
- package/dist/esm/components/navigation/app-level/sidebar.js.map +1 -1
- package/dist/esm/components/navigation/app-level/status-bar.js +2 -2
- package/dist/esm/components/navigation/app-level/status-bar.js.map +1 -1
- package/dist/esm/components/navigation/app-level/toolbar.d.ts.map +1 -1
- package/dist/esm/components/navigation/app-level/toolbar.js +2 -2
- package/dist/esm/components/navigation/app-level/toolbar.js.map +1 -1
- package/dist/esm/components/navigation/app-level/utility-panel.js +2 -2
- package/dist/esm/components/navigation/app-level/utility-panel.js.map +1 -1
- package/dist/esm/components/navigation/breadcrumb.js +1 -1
- package/dist/esm/components/navigation/breadcrumb.js.map +1 -1
- package/dist/esm/components/sections/stepper.d.ts.map +1 -1
- package/dist/esm/components/sections/stepper.js +5 -3
- package/dist/esm/components/sections/stepper.js.map +1 -1
- package/dist/esm/config/preset-navigation.d.ts.map +1 -1
- package/dist/esm/config/preset-navigation.js +23 -2
- package/dist/esm/config/preset-navigation.js.map +1 -1
- package/dist/esm/config/resources/agent-work.resource-presets.d.ts +4 -0
- package/dist/esm/config/resources/agent-work.resource-presets.d.ts.map +1 -0
- package/dist/esm/config/resources/agent-work.resource-presets.js +115 -0
- package/dist/esm/config/resources/agent-work.resource-presets.js.map +1 -0
- package/dist/esm/config/resources/api-key-rotation-window.d.ts +22 -0
- package/dist/esm/config/resources/api-key-rotation-window.d.ts.map +1 -0
- package/dist/esm/config/resources/api-key-rotation-window.js +45 -0
- package/dist/esm/config/resources/api-key-rotation-window.js.map +1 -0
- package/dist/esm/config/resources/application.resource-presets.d.ts.map +1 -1
- package/dist/esm/config/resources/application.resource-presets.js +147 -61
- package/dist/esm/config/resources/application.resource-presets.js.map +1 -1
- package/dist/esm/config/resources/billing.resource-presets.d.ts +4 -3
- package/dist/esm/config/resources/billing.resource-presets.d.ts.map +1 -1
- package/dist/esm/config/resources/billing.resource-presets.js +240 -111
- package/dist/esm/config/resources/billing.resource-presets.js.map +1 -1
- package/dist/esm/config/resources/conversation-threads.resource-presets.d.ts +4 -0
- package/dist/esm/config/resources/conversation-threads.resource-presets.d.ts.map +1 -0
- package/dist/esm/config/resources/conversation-threads.resource-presets.js +105 -0
- package/dist/esm/config/resources/conversation-threads.resource-presets.js.map +1 -0
- package/dist/esm/config/resources/guidance.resource-presets.d.ts.map +1 -1
- package/dist/esm/config/resources/guidance.resource-presets.js +18 -11
- package/dist/esm/config/resources/guidance.resource-presets.js.map +1 -1
- package/dist/esm/config/resources/identity.resource-presets.d.ts +0 -13
- package/dist/esm/config/resources/identity.resource-presets.d.ts.map +1 -1
- package/dist/esm/config/resources/identity.resource-presets.js +48 -16
- package/dist/esm/config/resources/identity.resource-presets.js.map +1 -1
- package/dist/esm/config/resources/inbound-deliveries.resource-presets.d.ts +6 -0
- package/dist/esm/config/resources/inbound-deliveries.resource-presets.d.ts.map +1 -0
- package/dist/esm/config/resources/inbound-deliveries.resource-presets.js +112 -0
- package/dist/esm/config/resources/inbound-deliveries.resource-presets.js.map +1 -0
- package/dist/esm/config/resources/inbound-email.resource-presets.d.ts +4 -0
- package/dist/esm/config/resources/inbound-email.resource-presets.d.ts.map +1 -0
- package/dist/esm/config/resources/inbound-email.resource-presets.js +182 -0
- package/dist/esm/config/resources/inbound-email.resource-presets.js.map +1 -0
- package/dist/esm/config/resources/index.d.ts.map +1 -1
- package/dist/esm/config/resources/index.js +9 -2
- package/dist/esm/config/resources/index.js.map +1 -1
- package/dist/esm/config/resources/legal-holds.resource-presets.d.ts +4 -0
- package/dist/esm/config/resources/legal-holds.resource-presets.d.ts.map +1 -0
- package/dist/esm/config/resources/legal-holds.resource-presets.js +76 -0
- package/dist/esm/config/resources/legal-holds.resource-presets.js.map +1 -0
- package/dist/esm/config/resources/organizations.resource-presets.d.ts.map +1 -1
- package/dist/esm/config/resources/organizations.resource-presets.js +139 -36
- package/dist/esm/config/resources/organizations.resource-presets.js.map +1 -1
- package/dist/esm/config/resources/resource.config.utils.d.ts +20 -0
- package/dist/esm/config/resources/resource.config.utils.d.ts.map +1 -1
- package/dist/esm/config/resources/resource.config.utils.js +20 -0
- package/dist/esm/config/resources/resource.config.utils.js.map +1 -1
- package/dist/esm/config/resources/retention-enforcement.resource-presets.d.ts +5 -0
- package/dist/esm/config/resources/retention-enforcement.resource-presets.d.ts.map +1 -0
- package/dist/esm/config/resources/retention-enforcement.resource-presets.js +74 -0
- package/dist/esm/config/resources/retention-enforcement.resource-presets.js.map +1 -0
- package/dist/esm/config/resources/security.resource-presets.d.ts +3 -1
- package/dist/esm/config/resources/security.resource-presets.d.ts.map +1 -1
- package/dist/esm/config/resources/security.resource-presets.js +563 -133
- package/dist/esm/config/resources/security.resource-presets.js.map +1 -1
- package/dist/esm/config/resources/service-providers.resource-presets.d.ts +4 -0
- package/dist/esm/config/resources/service-providers.resource-presets.d.ts.map +1 -0
- package/dist/esm/config/resources/service-providers.resource-presets.js +321 -0
- package/dist/esm/config/resources/service-providers.resource-presets.js.map +1 -0
- package/dist/esm/config/resources/webhooks.resource-presets.d.ts +4 -3
- package/dist/esm/config/resources/webhooks.resource-presets.d.ts.map +1 -1
- package/dist/esm/config/resources/webhooks.resource-presets.js +76 -25
- package/dist/esm/config/resources/webhooks.resource-presets.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/registration/register-common-enums.d.ts.map +1 -1
- package/dist/esm/registration/register-common-enums.js +15 -0
- package/dist/esm/registration/register-common-enums.js.map +1 -1
- package/dist/esm/registration/register-provider-components.d.ts.map +1 -1
- package/dist/esm/registration/register-provider-components.js +6 -0
- package/dist/esm/registration/register-provider-components.js.map +1 -1
- package/dist/esm/themes/dense.theme.d.ts.map +1 -1
- package/dist/esm/themes/dense.theme.js +22 -2
- package/dist/esm/themes/dense.theme.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +8 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.js","sourceRoot":"","sources":["../../../../../src/components/form/combobox.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EACL,EAAE,EACF,eAAe,EACf,qBAAqB,EACrB,QAAQ,EACR,OAAO,EACP,KAAK,EACL,MAAM,EACN,KAAK,EACL,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,WAAW,EACX,OAAO,EACP,cAAc,EACd,cAAc,EACd,cAAc,GACf,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AACpE,OAAO,EAAc,kBAAkB,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AACvH,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAG1D,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAA6B,SAAS,aAAa,CAClF,EACE,MAAM,EACN,IAAI,EACJ,OAAO,EACP,KAAK,EAAE,eAAe,EACtB,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,SAAS,EACT,IAAI,GAAG,IAAI,EACX,YAAY,EACZ,mBAAmB,EACnB,OAAO,EACP,gBAAgB,EAChB,cAAc,EACd,SAAS,EACT,YAAY,GAAG,IAAI,EACnB,YAAY,EAAE,gBAAgB,EAC9B,qBAAqB,GACtB,EACD,GAAG;IAEH,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAA;IACtE,MAAM,EAAE,UAAU,EAAE,GAAG,eAAe,EAAE,CAAA;IACxC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACtC,SAAS,EAAE,qBAAqB,CAAC,oBAAoB;KACtD,CAAC,CAAA;IACF,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,CAAA;IAC7B,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC,YAAY,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAA;IAEjF,MAAM,YAAY,GAAG,eAAe,KAAK,SAAS,CAAA;IAClD,MAAM,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa,CAAA;IAEnE,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAClC,GAAG,EAAE;QACH,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,YAAY,CAAC,CAAA;QACzD,IAAI,KAAK;YAAE,OAAO,KAAK,CAAA;QACvB,kEAAkE;QAClE,wEAAwE;QACxE,qEAAqE;QACrE,6DAA6D;QAC7D,sEAAsE;QACtE,wEAAwE;QACxE,mEAAmE;QACnE,8CAA8C;QAC9C,EAAE;QACF,wDAAwD;QACxD,wEAAwE;QACxE,uEAAuE;QACvE,sEAAsE;QACtE,qEAAqE;QACrE,sEAAsE;QACtE,IAAI,YAAY,IAAI,mBAAmB,EAAE,CAAC;YACxC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,CAAC,YAAY,CAAC,EAA4B,CAAA;QACvF,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC,EACD,CAAC,OAAO,EAAE,YAAY,EAAE,mBAAmB,CAAC,CAC7C,CAAA;IAED,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,aAAqB,EAAE,EAAE;QAC/D,MAAM,QAAQ,GAAG,aAAa,KAAK,YAAY,CAAC,CAAC,CAAE,EAA0B,CAAC,CAAC,CAAE,aAAqC,CAAA;QACtH,IAAI,YAAY,EAAE,CAAC;YACjB,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAA;QACtB,CAAC;aAAM,CAAC;YACN,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QAC5B,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,CAAA;QACd,gBAAgB,EAAE,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAA;IAE5D,MAAM,gBAAgB,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,MAAe,EAAE,EAAE;QAC7D,OAAO,CAAC,MAAM,CAAC,CAAA;QACf,gBAAgB,EAAE,CAAC,MAAM,CAAC,CAAA;QAC1B,IAAI,CAAC,MAAM;YAAE,MAAM,EAAE,EAAE,CAAA;IACzB,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAA;IAE9B,MAAM,OAAO,GAAG,SAAS,IAAI,EAAE,CAAA;IAE/B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,OAAO,CACL,MAAC,OAAO,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,gBAAgB,aACjD,KAAC,cAAc,IAAC,OAAO,kBACrB,MAAC,MAAM,IACL,GAAG,EAAE,GAAG,EACR,EAAE,EAAE,OAAO,EACX,OAAO,EAAE,sBAAsB,CAAC,OAAO,EACvC,IAAI,EAAC,UAAU,mBACA,IAAI,EACnB,QAAQ,EAAE,QAAQ,IAAI,QAAQ,EAC9B,SAAS,EAAE,SAAS,eACT,IAAI;oBACf;;;;gDAI4B;oBAC5B,IAAI,EAAE,IAAkB,EACxB,SAAS,EAAE,EAAE,CACX,oCAAoC,EACpC,CAAC,cAAc,IAAI,uBAAuB,EAC1C,UAAU,CAAC,MAAM,CAAC,KAAK,EACvB,UAAU,CAAC,MAAM,CAAC,QAAQ,EAC1B,UAAU,CAAC,MAAM,CAAC,UAAU,EAC5B,SAAS,CACV,aAKA,gBAAgB,IAAI,CACnB,4BAAgB,4BAA4B,EAAC,SAAS,EAAC,mCAAmC,iBAAa,MAAM,YAC1G,gBAAgB,GACZ,CACR,EAED,eAAM,SAAS,EAAC,kDAAkD,YAC/D,cAAc;gCACb,CAAC,CAAC,CAAC,mBAAmB;oCAClB,CAAC,CAAC,mBAAmB,CAAC,cAAc,CAAC;oCACrC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC;gCAC3B,CAAC,CAAC,CAAC,WAAW,IAAI,UAAU,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,mBAAmB,CAAC,CAAC,GAC3F,EAKN,OAAO,IAAI,cAAc,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,CACtD,eACE,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,CAAC,eACD,gBAAgB,gBACd,UAAU,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,OAAO,CAAC,EAC3E,SAAS,EAAE,EAAE,CACX,kEAAkE,EAClE,qEAAqE,EACrE,yEAAyE,CAC1E,EACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gCACjB,KAAK,CAAC,cAAc,EAAE,CAAA;gCACtB,KAAK,CAAC,eAAe,EAAE,CAAA;gCACvB,OAAO,EAAE,CAAA;4BACX,CAAC,EACD,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;gCACnB,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG;oCAAE,OAAM;gCACtD,KAAK,CAAC,cAAc,EAAE,CAAA;gCACtB,KAAK,CAAC,eAAe,EAAE,CAAA;gCACvB,OAAO,EAAE,CAAA;4BACX,CAAC,YAEA,UAAU,CAAC,qBAAqB,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,GAC1D,CACR,EACA,UAAU,CAAC,qBAAqB,CAAC,gBAAgB,EAAE;4BAClD,IAAI,EAAE,QAAQ,CAAC,EAAE;4BACjB,SAAS,EAAE,8CAA8C;yBAC1D,CAAC,IACK,GACM,EACjB,KAAC,cAAc,IAAC,SAAS,EAAC,uCAAuC,EAAC,KAAK,EAAE,eAAe,CAAC,KAAK,EAAE,qBAAqB,EAAE,qBAAqB,YAC1I,MAAC,OAAO,IAAC,YAAY,EAAE,YAAY,aACjC,KAAC,YAAY,IACX,WAAW,EAAE,iBAAiB,IAAI,UAAU,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,mBAAmB,CAAC,EAC7G,aAAa,EAAE,cAAc,GAC7B,EACF,MAAC,WAAW,eAKV,KAAC,YAAY,cACV,SAAS;wCACR,CAAC,CAAC,KAAC,gBAAgB,KAAG;wCACtB,CAAC,CAAC,CAAC,YAAY,IAAI,UAAU,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC,GAC5E,EACf,KAAC,YAAY,cACV,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;wCACtB,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,KAAK,YAAY,CAAA;wCAChD,OAAO,CACL,MAAC,WAAW,IAEV,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,QAAQ,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EACxB,QAAQ,EAAE,MAAM,CAAC,QAAQ,EACzB,QAAQ,EAAE,YAAY,aAErB,UAAU,CAAC,qBAAqB,CAAC,KAAK,EAAE;oDACvC,IAAI,EAAE,QAAQ,CAAC,EAAE;oDACjB,SAAS,EAAE,EAAE,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC;iDACzE,CAAC,EACD,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,KAV1D,MAAM,CAAC,KAAK,CAWL,CACf,CAAA;oCACH,CAAC,CAAC,GACW,IACH,IACN,GACK,IACT,CACX,CAAA;AACH,CAAC,CAAC,CAAA;AACF,QAAQ,CAAC,WAAW,GAAG,UAAU,CAAA;AAEjC,MAAM,gBAAgB,GAAG,KAAK,CAAC,UAAU,CAA6C,SAAS,qBAAqB,CAClH,EACE,MAAM,EACN,IAAI,EACJ,OAAO,EACP,KAAK,EAAE,eAAe,EACtB,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,SAAS,EACT,IAAI,GAAG,IAAI,EACX,kBAAkB,GAAG,CAAC,EACtB,aAAa,GAAG,IAAI,EACpB,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,SAAS,EACT,YAAY,GAAG,IAAI,EACnB,YAAY,EAAE,gBAAgB,EAC9B,qBAAqB,GACtB,EACD,GAAG;IAEH,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAW,YAAY,IAAI,EAAE,CAAC,CAAA;IACtF,MAAM,EAAE,UAAU,EAAE,GAAG,eAAe,EAAE,CAAA;IACxC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACtC,SAAS,EAAE,qBAAqB,CAAC,oBAAoB;KACtD,CAAC,CAAA;IACF,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,CAAA;IAC7B,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC,YAAY,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAA;IAEjF,MAAM,YAAY,GAAG,eAAe,KAAK,SAAS,CAAA;IAClD,MAAM,YAAY,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa,CAAa,CAAA;IAEjF,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAA;IAE9E,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,QAAkB,EAAE,EAAE;QACxD,IAAI,YAAY,EAAE,CAAC;YACjB,QAAQ,EAAE,CAAC,QAA+B,CAAC,CAAA;QAC7C,CAAC;aAAM,CAAC;YACN,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QAC5B,CAAC;IACH,CAAC,EAAE,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE5B,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,WAAmB,EAAE,EAAE;QAC7D,IAAI,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YACjC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,CAAA;QACvD,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,CAAC,GAAG,YAAY,EAAE,WAAW,CAAC,CAAC,CAAA;QAC1C,CAAC;IACH,CAAC,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEzC,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,WAAmB,EAAE,EAAE;QAC7D,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,CAAA;IACvD,CAAC,EAAE,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE5B,MAAM,gBAAgB,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,MAAe,EAAE,EAAE;QAC7D,OAAO,CAAC,MAAM,CAAC,CAAA;QACf,gBAAgB,EAAE,CAAC,MAAM,CAAC,CAAA;QAC1B,IAAI,CAAC,MAAM;YAAE,MAAM,EAAE,EAAE,CAAA;IACzB,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAA;IAE9B,MAAM,iBAAiB,GAAG,KAAK,CAAC,OAAO,CACrC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EACtC,CAAC,OAAO,CAAC,CACV,CAAA;IACD,MAAM,gBAAgB,GAAG,KAAK,CAAC,OAAO,CACpC,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAClD,CAAC,iBAAiB,CAAC,CACpB,CAAA;IACD,MAAM,uBAAuB,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;IACxF,MAAM,WAAW,GAAG,uBAAuB,IAAI,iBAAiB,CAAC,MAAM,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAA;IAEvG,MAAM,eAAe,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QAC7C,QAAQ,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;IAC/C,CAAC,EAAE,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEjC,MAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QAC5C,QAAQ,CAAC,EAAE,CAAC,CAAA;IACd,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEd,MAAM,OAAO,GAAG,SAAS,IAAI,EAAE,CAAA;IAC/B,MAAM,eAAe,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAA;IACjE,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,GAAG,eAAe,CAAC,MAAM,CAAA;IAElE,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,OAAO,CACL,eAAK,SAAS,EAAE,EAAE,CAAC,2BAA2B,EAAE,SAAS,CAAC,aACxD,MAAC,OAAO,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,gBAAgB,aACjD,KAAC,cAAc,IAAC,OAAO,kBACrB,MAAC,MAAM,IACL,GAAG,EAAE,GAAG,EACR,EAAE,EAAE,OAAO,EACX,OAAO,EAAE,sBAAsB,CAAC,OAAO,EACvC,IAAI,EAAC,UAAU,mBACA,IAAI,EACnB,QAAQ,EAAE,QAAQ,IAAI,QAAQ,EAC9B,SAAS,EAAE,SAAS,eACT,IAAI;4BACf;;;;uFAI2D;4BAC3D,SAAS,EAAE,EAAE,CACX,4CAA4C,EAC5C,IAAI,KAAK,IAAI,IAAI,SAAS,EAC1B,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,uBAAuB,EACpD,UAAU,CAAC,MAAM,CAAC,KAAK,EACvB,UAAU,CAAC,MAAM,CAAC,QAAQ,EAC1B,UAAU,CAAC,MAAM,CAAC,UAAU,CAC7B,aAED,eAAM,SAAS,EAAC,UAAU,YACvB,YAAY,CAAC,MAAM,KAAK,CAAC;wCACxB,CAAC,CAAC,CAAC,WAAW,IAAI,UAAU,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,mBAAmB,CAAC,CAAC;wCAC9F,CAAC,CAAC,UAAU,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,eAAe,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,GAC9G,EACN,UAAU,CAAC,qBAAqB,CAAC,gBAAgB,EAAE;oCAClD,IAAI,EAAE,QAAQ,CAAC,EAAE;oCACjB,SAAS,EAAE,8CAA8C;iCAC1D,CAAC,IACK,GACM,EACjB,KAAC,cAAc,IAAC,SAAS,EAAC,uCAAuC,EAAC,KAAK,EAAE,eAAe,CAAC,KAAK,EAAE,qBAAqB,EAAE,qBAAqB,YAC1I,MAAC,OAAO,IAAC,YAAY,EAAE,YAAY,aACjC,KAAC,YAAY,IACX,WAAW,EAAE,iBAAiB,IAAI,UAAU,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,mBAAmB,CAAC,EAC7G,aAAa,EAAE,cAAc,GAC7B,EACF,MAAC,WAAW,eAKV,KAAC,YAAY,cACV,SAAS;gDACR,CAAC,CAAC,KAAC,gBAAgB,KAAG;gDACtB,CAAC,CAAC,CAAC,YAAY,IAAI,UAAU,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC,GAC5E,EACf,MAAC,YAAY,eACV,aAAa,IAAI,CAAC,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CACpD,KAAC,WAAW,IACV,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,eAAe,EACxD,SAAS,EAAC,8CAA8C,YAEvD,WAAW;wDACV,CAAC,CAAC,UAAU,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,UAAU,CAAC;wDACpE,CAAC,CAAC,UAAU,CAAC,qBAAqB,CAAC,oBAAoB,EAAE,WAAW,CAAC,GAC3D,CACf,EACA,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;oDACtB,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oDAChD,OAAO,CACL,MAAC,WAAW,IAEV,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,QAAQ,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EACxB,QAAQ,EAAE,MAAM,CAAC,QAAQ,EACzB,QAAQ,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,aAE1C,cAAK,SAAS,EAAE,EAAE,CAChB,wFAAwF,EACxF,UAAU,CAAC,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC,gCAAgC,CACrF,YACE,UAAU,IAAI,UAAU,CAAC,qBAAqB,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,GACzE,EACL,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,KAZ1D,MAAM,CAAC,KAAK,CAaL,CACf,CAAA;gDACH,CAAC,CAAC,IACW,IACH,IACN,GACK,IACT,EAOT,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,CAC1B,eAAK,SAAS,EAAC,+BAA+B,aAC3C,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;wBACzB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAA;wBAC5C,yFAAyF;wBACzF,OAAO,CACL,MAAC,KAAK,IAAS,OAAO,EAAC,WAAW,EAAC,SAAS,EAAC,MAAM,aAChD,GAAG,IAAI,mBAAmB;oCACzB,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC;oCAC1B,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC,EACpB,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,CACzB,iBACE,IAAI,EAAC,QAAQ,gBACD,UAAU,GAAG,EAAE,KAAK,IAAI,CAAC,EAAE,EACvC,SAAS,EAAC,iHAAiH,EAC3H,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,YAE7B,UAAU,CAAC,qBAAqB,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,GACzD,CACV,KAbS,CAAC,CAcL,CACT,CAAA;oBACH,CAAC,CAAC,EACD,aAAa,GAAG,CAAC,IAAI,CACpB,MAAC,KAAK,IAAC,OAAO,EAAC,WAAW,EAAC,SAAS,EAAC,uBAAuB,kBACxD,aAAa,IACT,CACT,IACG,CACP,IACG,CACP,CAAA;AACH,CAAC,CAAC,CAAA;AACF,gBAAgB,CAAC,WAAW,GAAG,kBAAkB,CAAA;AAEjD,SAAS,gBAAgB;IACvB,OAAO,CACL,cAAK,SAAS,EAAC,6CAA6C,YAC1D,KAAC,cAAc,IAAC,IAAI,EAAE,EAAE,GAAI,GACxB,CACP,CAAA;AACH,CAAC;AAED,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAA","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport {\n cn,\n useIconRegistry,\n StandardIconReference,\n IconSize,\n useI18n,\n useUI,\n Button,\n Badge,\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n Popover,\n PopoverContent,\n PopoverTrigger,\n LoadingSpinner,\n} from \"@wildo-ai/saas-frontend-lib\"\nimport { ButtonVariants_Variant } from \"@wildo-ai/saas-frontend-lib\"\nimport { ButtonSize, FormControlVariant, FrontendComponentType, UIBehavior } from \"@wildo-ai/presets-components-models\"\nimport { HorizontalAlign } from \"@wildo-ai/zod-decorators\"\nimport type { ComboboxProps, ComboboxRef, ComboboxMultipleProps, ComboboxMultipleRef, FieldOption } from \"@wildo-ai/saas-frontend-lib\"\n\nconst Combobox = React.forwardRef<ComboboxRef, ComboboxProps>(function ComboboxInner(\n {\n schema,\n name,\n options,\n value: controlledValue,\n onChange,\n onBlur,\n defaultValue,\n placeholder,\n searchPlaceholder,\n emptyMessage,\n disabled,\n readOnly,\n className,\n autoFocus,\n size = \"md\",\n renderOption,\n renderSelectedValue,\n onClear,\n leadingAdornment,\n onSearchChange,\n isLoading,\n shouldFilter = true,\n onOpenChange: onOpenChangeProp,\n surfacePolicyOverride,\n },\n ref\n): React.JSX.Element | null {\n const [open, setOpen] = React.useState(false)\n const [internalValue, setInternalValue] = React.useState(defaultValue)\n const { renderIcon } = useIconRegistry()\n const { tComponent, isReady } = useI18n({\n component: FrontendComponentType.LOW_LEVEL_FORM_FIELD,\n })\n const { getRecipe } = useUI()\n const formRecipe = getRecipe(UIBehavior.FORM_CONTROL, FormControlVariant.DEFAULT)\n\n const isControlled = controlledValue !== undefined\n const currentValue = isControlled ? controlledValue : internalValue\n\n const selectedOption = React.useMemo(\n () => {\n const match = options.find(o => o.value === currentValue)\n if (match) return match\n // Async-options comboboxes (resource-reference pickers, the quick\n // switcher) fetch their options lazily on OPEN, so a persisted/restored\n // selection has no matching option object on a cold mount. Supplying\n // `renderSelectedValue` is the contract that the CALLER owns\n // selected-label rendering (the resource-reference preset resolves it\n // via a record READ independently of the options list), so synthesize a\n // value-only option instead of degrading the CLOSED trigger to the\n // placeholder while a real value is selected.\n //\n // Consequence for STATIC-options callers that also pass\n // `renderSelectedValue` (e.g. FormFieldEnum): a value outside `options`\n // now renders through their callback (typically the raw value) instead\n // of the placeholder — an honest \"unknown value\" display, deliberate.\n // Callers that pass NO `renderSelectedValue` keep the strict options\n // match: for them a value outside `options` has no displayable label.\n if (currentValue && renderSelectedValue) {\n return { value: currentValue, label: String(currentValue) } as typeof options[number]\n }\n return undefined\n },\n [options, currentValue, renderSelectedValue]\n )\n\n const handleSelect = React.useCallback((selectedValue: string) => {\n const newValue = selectedValue === currentValue ? ('' as typeof currentValue) : (selectedValue as typeof currentValue)\n if (isControlled) {\n onChange?.(newValue)\n } else {\n setInternalValue(newValue)\n }\n setOpen(false)\n onOpenChangeProp?.(false)\n }, [currentValue, isControlled, onChange, onOpenChangeProp])\n\n const handleOpenChange = React.useCallback((isOpen: boolean) => {\n setOpen(isOpen)\n onOpenChangeProp?.(isOpen)\n if (!isOpen) onBlur?.()\n }, [onBlur, onOpenChangeProp])\n\n const fieldId = `field-${name}`\n\n if (!isReady) return null;\n\n return (\n <Popover open={open} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <Button\n ref={ref}\n id={fieldId}\n variant={ButtonVariants_Variant.OUTLINE}\n role=\"combobox\"\n aria-expanded={open}\n disabled={disabled || readOnly}\n autoFocus={autoFocus}\n data-size={size}\n /* V-5.c: ControlSize and ButtonSize share keys (sm/md) so we\n pass the form-control size straight through to Button rather\n than overriding height with a className. The form recipe\n still drives focus/disabled/motion because the trigger lives\n inside a form context. */\n size={size as ButtonSize}\n className={cn(\n \"w-full justify-between font-normal\",\n !selectedOption && \"text-muted-foreground\",\n formRecipe.states.focus,\n formRecipe.states.disabled,\n formRecipe.motion.transition,\n className,\n )}\n >\n {/* Leading adornment — presentational identity (e.g. the scoped\n resource's icon). `aria-hidden`: the control's accessible name is\n its label, and a decorative glyph must not add noise to it. */}\n {leadingAdornment && (\n <span data-slot=\"combobox-leading-adornment\" className=\"shrink-0 inline-flex items-center\" aria-hidden=\"true\">\n {leadingAdornment}\n </span>\n )}\n {/* `element` is the glyph-beside-its-word role; `item-xs` resolved to one pixel. */}\n <span className=\"inline-flex items-center gap-element-sm truncate\">\n {selectedOption\n ? (renderSelectedValue\n ? renderSelectedValue(selectedOption)\n : selectedOption.label)\n : (placeholder ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'selectPlaceholder'))}\n </span>\n {/* CLEAR — inside the control, before the chevron. It is a real\n button nested in the trigger button's slot, so the click must not\n bubble into the trigger (which would reopen the popover the clear\n just made unnecessary) and must not submit an enclosing form. */}\n {onClear && selectedOption && !disabled && !readOnly && (\n <span\n role=\"button\"\n tabIndex={0}\n data-slot=\"combobox-clear\"\n aria-label={tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'clear')}\n className={cn(\n \"ms-2 shrink-0 inline-flex items-center justify-center rounded-sm\",\n \"opacity-[var(--opacity-muted)] hover:opacity-100 transition-opacity\",\n \"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n )}\n onClick={(event) => {\n event.preventDefault()\n event.stopPropagation()\n onClear()\n }}\n onKeyDown={(event) => {\n if (event.key !== 'Enter' && event.key !== ' ') return\n event.preventDefault()\n event.stopPropagation()\n onClear()\n }}\n >\n {renderIcon(StandardIconReference.CLOSE, { size: IconSize.SM })}\n </span>\n )}\n {renderIcon(StandardIconReference.CHEVRONS_UP_DOWN, {\n size: IconSize.SM,\n className: \"ms-2 shrink-0 opacity-[var(--opacity-muted)]\",\n })}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[--radix-popover-trigger-width] p-0\" align={HorizontalAlign.START} surfacePolicyOverride={surfacePolicyOverride}>\n <Command shouldFilter={shouldFilter}>\n <CommandInput\n placeholder={searchPlaceholder ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'searchPlaceholder')}\n onValueChange={onSearchChange}\n />\n <CommandList>\n {/* CommandEmpty is the SOLE loading/empty surface: cmdk renders it\n whenever zero CommandItems exist, and a spinner placed inside\n <CommandGroup> is not an item — it stacks a second spinner\n under this one instead of suppressing it. */}\n <CommandEmpty>\n {isLoading\n ? <LoadingIndicator />\n : (emptyMessage ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'noResults'))}\n </CommandEmpty>\n <CommandGroup>\n {options.map((option) => {\n const isSelected = option.value === currentValue\n return (\n <CommandItem\n key={option.value}\n value={option.value}\n keywords={[option.label]}\n disabled={option.disabled}\n onSelect={handleSelect}\n >\n {renderIcon(StandardIconReference.CHECK, {\n size: IconSize.SM,\n className: cn(\"me-2 shrink-0\", isSelected ? \"opacity-100\" : \"opacity-0\"),\n })}\n {renderOption ? renderOption(option, isSelected) : option.label}\n </CommandItem>\n )\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n )\n})\nCombobox.displayName = \"Combobox\"\n\nconst ComboboxMultiple = React.forwardRef<ComboboxMultipleRef, ComboboxMultipleProps>(function ComboboxMultipleInner(\n {\n schema,\n name,\n options,\n value: controlledValue,\n onChange,\n onBlur,\n defaultValue,\n placeholder,\n searchPlaceholder,\n emptyMessage,\n disabled,\n readOnly,\n className,\n autoFocus,\n size = \"md\",\n maxDisplayedBadges = 5,\n showSelectAll = true,\n renderOption,\n renderSelectedValue,\n onSearchChange,\n isLoading,\n shouldFilter = true,\n onOpenChange: onOpenChangeProp,\n surfacePolicyOverride,\n },\n ref\n): React.JSX.Element | null {\n const [open, setOpen] = React.useState(false)\n const [internalValue, setInternalValue] = React.useState<string[]>(defaultValue ?? [])\n const { renderIcon } = useIconRegistry()\n const { tComponent, isReady } = useI18n({\n component: FrontendComponentType.LOW_LEVEL_FORM_FIELD,\n })\n const { getRecipe } = useUI()\n const formRecipe = getRecipe(UIBehavior.FORM_CONTROL, FormControlVariant.DEFAULT)\n\n const isControlled = controlledValue !== undefined\n const currentValue = (isControlled ? controlledValue : internalValue) as string[]\n\n const selectedSet = React.useMemo(() => new Set(currentValue), [currentValue])\n\n const setValue = React.useCallback((newValue: string[]) => {\n if (isControlled) {\n onChange?.(newValue as typeof currentValue)\n } else {\n setInternalValue(newValue)\n }\n }, [isControlled, onChange])\n\n const handleToggle = React.useCallback((optionValue: string) => {\n if (selectedSet.has(optionValue)) {\n setValue(currentValue.filter(v => v !== optionValue))\n } else {\n setValue([...currentValue, optionValue])\n }\n }, [selectedSet, currentValue, setValue])\n\n const handleRemove = React.useCallback((optionValue: string) => {\n setValue(currentValue.filter(v => v !== optionValue))\n }, [currentValue, setValue])\n\n const handleOpenChange = React.useCallback((isOpen: boolean) => {\n setOpen(isOpen)\n onOpenChangeProp?.(isOpen)\n if (!isOpen) onBlur?.()\n }, [onBlur, onOpenChangeProp])\n\n const selectableOptions = React.useMemo(\n () => options.filter(o => !o.disabled),\n [options]\n )\n const selectableValues = React.useMemo(\n () => new Set(selectableOptions.map(o => o.value)),\n [selectableOptions]\n )\n const selectedSelectableCount = currentValue.filter(v => selectableValues.has(v)).length\n const allSelected = selectedSelectableCount >= selectableOptions.length && selectableOptions.length > 0\n\n const handleSelectAll = React.useCallback(() => {\n setValue(selectableOptions.map(o => o.value))\n }, [selectableOptions, setValue])\n\n const handleClearAll = React.useCallback(() => {\n setValue([])\n }, [setValue])\n\n const fieldId = `field-${name}`\n const displayedBadges = currentValue.slice(0, maxDisplayedBadges)\n const overflowCount = currentValue.length - displayedBadges.length\n\n if (!isReady) return null;\n\n return (\n <div className={cn(\"flex flex-col gap-item-xs\", className)}>\n <Popover open={open} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <Button\n ref={ref}\n id={fieldId}\n variant={ButtonVariants_Variant.OUTLINE}\n role=\"combobox\"\n aria-expanded={open}\n disabled={disabled || readOnly}\n autoFocus={autoFocus}\n data-size={size}\n /* V-5.c: multi-select uses `min-h-*` (not `h-*`) because the\n trigger grows vertically as chips wrap. We deliberately do\n NOT pass `size` to Button here — Button's recipe uses fixed\n `h-*`, which would clip wrapped chip rows. The recipe's\n focus/disabled/motion still apply via the cn() merge. */\n className={cn(\n \"w-full justify-between font-normal min-h-9\",\n size === \"sm\" && \"min-h-8\",\n currentValue.length === 0 && \"text-muted-foreground\",\n formRecipe.states.focus,\n formRecipe.states.disabled,\n formRecipe.motion.transition,\n )}\n >\n <span className=\"truncate\">\n {currentValue.length === 0\n ? (placeholder ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'selectPlaceholder'))\n : tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'selectedCount', { count: String(currentValue.length) })}\n </span>\n {renderIcon(StandardIconReference.CHEVRONS_UP_DOWN, {\n size: IconSize.SM,\n className: \"ms-2 shrink-0 opacity-[var(--opacity-muted)]\",\n })}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[--radix-popover-trigger-width] p-0\" align={HorizontalAlign.START} surfacePolicyOverride={surfacePolicyOverride}>\n <Command shouldFilter={shouldFilter}>\n <CommandInput\n placeholder={searchPlaceholder ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'searchPlaceholder')}\n onValueChange={onSearchChange}\n />\n <CommandList>\n {/* CommandEmpty is the SOLE loading/empty surface: cmdk renders\n it whenever zero CommandItems exist, and a spinner placed\n inside <CommandGroup> is not an item — it stacks a second\n spinner under this one instead of suppressing it. */}\n <CommandEmpty>\n {isLoading\n ? <LoadingIndicator />\n : (emptyMessage ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'noResults'))}\n </CommandEmpty>\n <CommandGroup>\n {showSelectAll && !isLoading && options.length > 0 && (\n <CommandItem\n onSelect={allSelected ? handleClearAll : handleSelectAll}\n className=\"justify-center text-xs text-muted-foreground\"\n >\n {allSelected\n ? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'clearAll')\n : tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'selectAll')}\n </CommandItem>\n )}\n {options.map((option) => {\n const isSelected = selectedSet.has(option.value)\n return (\n <CommandItem\n key={option.value}\n value={option.value}\n keywords={[option.label]}\n disabled={option.disabled}\n onSelect={() => handleToggle(option.value)}\n >\n <div className={cn(\n \"me-2 flex size-4 shrink-0 items-center justify-center rounded-sm border border-primary\",\n isSelected ? \"bg-primary text-primary-foreground\" : \"opacity-[var(--opacity-muted)]\",\n )}>\n {isSelected && renderIcon(StandardIconReference.CHECK, { size: IconSize.XS })}\n </div>\n {renderOption ? renderOption(option, isSelected) : option.label}\n </CommandItem>\n )\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n\n {/*\n * The chip row's gap is `element`: that role's own definition is \"between inline elements\n * (icons, buttons, TAGS)\". It was `item-xs`, and `--sp-item` at a quarter is one pixel, so\n * the chips abutted each other.\n */}\n {currentValue.length > 0 && (\n <div className=\"flex flex-wrap gap-element-sm\">\n {displayedBadges.map((v) => {\n const opt = options.find(o => o.value === v)\n /* No local gap on the chip: `Badge`'s own structure owns the space between its parts. */\n return (\n <Badge key={v} variant=\"secondary\" className=\"pe-1\">\n {opt && renderSelectedValue\n ? renderSelectedValue(opt)\n : (opt?.label ?? v)}\n {!readOnly && !disabled && (\n <button\n type=\"button\"\n aria-label={`Remove ${opt?.label ?? v}`}\n className=\"ms-0.5 rounded-full p-0.5 hover:bg-muted-foreground/20 transition-colors duration-[var(--motion-duration-fast)]\"\n onClick={() => handleRemove(v)}\n >\n {renderIcon(StandardIconReference.X_MARK, { size: IconSize.XS })}\n </button>\n )}\n </Badge>\n )\n })}\n {overflowCount > 0 && (\n <Badge variant=\"secondary\" className=\"text-muted-foreground\">\n +{overflowCount}\n </Badge>\n )}\n </div>\n )}\n </div>\n )\n})\nComboboxMultiple.displayName = \"ComboboxMultiple\"\n\nfunction LoadingIndicator(): React.JSX.Element {\n return (\n <div className=\"flex items-center justify-center py-card-sm\">\n <LoadingSpinner size={16} />\n </div>\n )\n}\n\nexport { Combobox, ComboboxMultiple }\n"]}
|
|
1
|
+
{"version":3,"file":"combobox.js","sourceRoot":"","sources":["../../../../../src/components/form/combobox.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport {\n cn,\n useIconRegistry,\n StandardIconReference,\n IconSize,\n useI18n,\n useUI,\n Button,\n Badge,\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n Popover,\n PopoverContent,\n PopoverTrigger,\n LoadingSpinner,\n} from \"@wildo-ai/saas-frontend-lib\"\nimport { ButtonVariants_Variant } from \"@wildo-ai/saas-frontend-lib\"\nimport { ButtonSize, FormControlVariant, FrontendComponentType, UIBehavior } from \"@wildo-ai/presets-components-models\"\nimport { HorizontalAlign } from \"@wildo-ai/zod-decorators\"\nimport type { ComboboxProps, ComboboxRef, ComboboxMultipleProps, ComboboxMultipleRef, FieldOption } from \"@wildo-ai/saas-frontend-lib\"\n\nconst Combobox = React.forwardRef<ComboboxRef, ComboboxProps>(function ComboboxInner(\n {\n schema,\n name,\n options,\n value: controlledValue,\n onChange,\n onBlur,\n defaultValue,\n placeholder,\n searchPlaceholder,\n emptyMessage,\n disabled,\n readOnly,\n className,\n autoFocus,\n size = \"md\",\n renderOption,\n renderSelectedValue,\n onClear,\n leadingAdornment,\n onSearchChange,\n isLoading,\n shouldFilter = true,\n onOpenChange: onOpenChangeProp,\n listFooter,\n surfacePolicyOverride,\n },\n ref\n): React.JSX.Element | null {\n const [open, setOpen] = React.useState(false)\n const [internalValue, setInternalValue] = React.useState(defaultValue)\n const { renderIcon } = useIconRegistry()\n const { tComponent, isReady } = useI18n({\n component: FrontendComponentType.LOW_LEVEL_FORM_FIELD,\n })\n const { getRecipe } = useUI()\n const formRecipe = getRecipe(UIBehavior.FORM_CONTROL, FormControlVariant.DEFAULT)\n\n const isControlled = controlledValue !== undefined\n const currentValue = isControlled ? controlledValue : internalValue\n\n const selectedOption = React.useMemo(\n () => {\n const match = options.find(o => o.value === currentValue)\n if (match) return match\n // Async-options comboboxes (resource-reference pickers, the quick\n // switcher) fetch their options lazily on OPEN, so a persisted/restored\n // selection has no matching option object on a cold mount. Supplying\n // `renderSelectedValue` is the contract that the CALLER owns\n // selected-label rendering (the resource-reference preset resolves it\n // via a record READ independently of the options list), so synthesize a\n // value-only option instead of degrading the CLOSED trigger to the\n // placeholder while a real value is selected.\n //\n // Consequence for STATIC-options callers that also pass\n // `renderSelectedValue` (e.g. FormFieldEnum): a value outside `options`\n // now renders through their callback (typically the raw value) instead\n // of the placeholder — an honest \"unknown value\" display, deliberate.\n // Callers that pass NO `renderSelectedValue` keep the strict options\n // match: for them a value outside `options` has no displayable label.\n if (currentValue && renderSelectedValue) {\n return { value: currentValue, label: String(currentValue) } as typeof options[number]\n }\n return undefined\n },\n [options, currentValue, renderSelectedValue]\n )\n\n const handleSelect = React.useCallback((selectedValue: string) => {\n const newValue = selectedValue === currentValue ? ('' as typeof currentValue) : (selectedValue as typeof currentValue)\n if (isControlled) {\n onChange?.(newValue)\n } else {\n setInternalValue(newValue)\n }\n setOpen(false)\n onOpenChangeProp?.(false)\n }, [currentValue, isControlled, onChange, onOpenChangeProp])\n\n const handleOpenChange = React.useCallback((isOpen: boolean) => {\n setOpen(isOpen)\n onOpenChangeProp?.(isOpen)\n if (!isOpen) onBlur?.()\n }, [onBlur, onOpenChangeProp])\n\n const fieldId = `field-${name}`\n\n if (!isReady) return null;\n\n return (\n <Popover open={open} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <Button\n ref={ref}\n id={fieldId}\n variant={ButtonVariants_Variant.OUTLINE}\n role=\"combobox\"\n aria-expanded={open}\n disabled={disabled || readOnly}\n autoFocus={autoFocus}\n data-size={size}\n /* V-5.c: ControlSize and ButtonSize share keys (sm/md) so we\n pass the form-control size straight through to Button rather\n than overriding height with a className. The form recipe\n still drives focus/disabled/motion because the trigger lives\n inside a form context. */\n size={size as ButtonSize}\n className={cn(\n \"w-full justify-between font-normal\",\n !selectedOption && \"text-muted-foreground\",\n formRecipe.states.focus,\n formRecipe.states.disabled,\n formRecipe.motion.transition,\n className,\n )}\n >\n {/* Leading adornment — presentational identity (e.g. the scoped\n resource's icon). `aria-hidden`: the control's accessible name is\n its label, and a decorative glyph must not add noise to it. */}\n {leadingAdornment && (\n <span data-slot=\"combobox-leading-adornment\" className=\"shrink-0 inline-flex items-center\" aria-hidden=\"true\">\n {leadingAdornment}\n </span>\n )}\n {/* `element` is the glyph-beside-its-word role; `item-xs` resolved to one pixel. */}\n <span className=\"inline-flex items-center gap-element-sm truncate\">\n {selectedOption\n ? (renderSelectedValue\n ? renderSelectedValue(selectedOption)\n : selectedOption.label)\n : (placeholder ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'selectPlaceholder'))}\n </span>\n {/* CLEAR — inside the control, before the chevron. It is a real\n button nested in the trigger button's slot, so the click must not\n bubble into the trigger (which would reopen the popover the clear\n just made unnecessary) and must not submit an enclosing form. */}\n {onClear && selectedOption && !disabled && !readOnly && (\n <span\n role=\"button\"\n tabIndex={0}\n data-slot=\"combobox-clear\"\n aria-label={tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'clear')}\n className={cn(\n \"ms-2 shrink-0 inline-flex items-center justify-center rounded-sm\",\n \"opacity-[var(--opacity-muted)] hover:opacity-100 transition-opacity\",\n \"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n )}\n onClick={(event) => {\n event.preventDefault()\n event.stopPropagation()\n onClear()\n }}\n onKeyDown={(event) => {\n if (event.key !== 'Enter' && event.key !== ' ') return\n event.preventDefault()\n event.stopPropagation()\n onClear()\n }}\n >\n {renderIcon(StandardIconReference.CLOSE, { size: IconSize.SM })}\n </span>\n )}\n {renderIcon(StandardIconReference.CHEVRONS_UP_DOWN, {\n size: IconSize.SM,\n className: \"ms-2 shrink-0 opacity-[var(--opacity-muted)]\",\n })}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[--radix-popover-trigger-width] p-0\" align={HorizontalAlign.START} surfacePolicyOverride={surfacePolicyOverride}>\n <Command shouldFilter={shouldFilter}>\n <CommandInput\n placeholder={searchPlaceholder ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'searchPlaceholder')}\n onValueChange={onSearchChange}\n />\n <CommandList>\n {/* CommandEmpty is the SOLE loading/empty surface: cmdk renders it\n whenever zero CommandItems exist, and a spinner placed inside\n <CommandGroup> is not an item — it stacks a second spinner\n under this one instead of suppressing it. */}\n <CommandEmpty>\n {isLoading\n ? <LoadingIndicator />\n : (emptyMessage ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'noResults'))}\n </CommandEmpty>\n <CommandGroup>\n {options.map((option) => {\n const isSelected = option.value === currentValue\n return (\n <CommandItem\n key={option.value}\n value={option.value}\n keywords={[option.label]}\n disabled={option.disabled}\n onSelect={handleSelect}\n >\n {renderIcon(StandardIconReference.CHECK, {\n size: IconSize.SM,\n className: cn(\"me-2 shrink-0\", isSelected ? \"opacity-100\" : \"opacity-0\"),\n })}\n {renderOption ? renderOption(option, isSelected) : option.label}\n </CommandItem>\n )\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n {/* Inside the popup, below the options: the same visual container as the results (`listFooter`). */}\n {listFooter ? (\n <div data-slot=\"combobox-list-footer\" className=\"border-t border-border px-element py-element-sm\">\n {listFooter}\n </div>\n ) : null}\n </PopoverContent>\n </Popover>\n )\n})\nCombobox.displayName = \"Combobox\"\n\nconst ComboboxMultiple = React.forwardRef<ComboboxMultipleRef, ComboboxMultipleProps>(function ComboboxMultipleInner(\n {\n schema,\n name,\n options,\n value: controlledValue,\n onChange,\n onBlur,\n defaultValue,\n placeholder,\n searchPlaceholder,\n emptyMessage,\n disabled,\n readOnly,\n className,\n autoFocus,\n size = \"md\",\n maxDisplayedBadges = 5,\n showSelectAll = true,\n renderOption,\n renderSelectedValue,\n onSearchChange,\n isLoading,\n shouldFilter = true,\n onOpenChange: onOpenChangeProp,\n surfacePolicyOverride,\n },\n ref\n): React.JSX.Element | null {\n const [open, setOpen] = React.useState(false)\n const [internalValue, setInternalValue] = React.useState<string[]>(defaultValue ?? [])\n const { renderIcon } = useIconRegistry()\n const { tComponent, isReady } = useI18n({\n component: FrontendComponentType.LOW_LEVEL_FORM_FIELD,\n })\n const { getRecipe } = useUI()\n const formRecipe = getRecipe(UIBehavior.FORM_CONTROL, FormControlVariant.DEFAULT)\n\n const isControlled = controlledValue !== undefined\n const currentValue = (isControlled ? controlledValue : internalValue) as string[]\n\n const selectedSet = React.useMemo(() => new Set(currentValue), [currentValue])\n\n const setValue = React.useCallback((newValue: string[]) => {\n if (isControlled) {\n onChange?.(newValue as typeof currentValue)\n } else {\n setInternalValue(newValue)\n }\n }, [isControlled, onChange])\n\n const handleToggle = React.useCallback((optionValue: string) => {\n if (selectedSet.has(optionValue)) {\n setValue(currentValue.filter(v => v !== optionValue))\n } else {\n setValue([...currentValue, optionValue])\n }\n }, [selectedSet, currentValue, setValue])\n\n const handleRemove = React.useCallback((optionValue: string) => {\n setValue(currentValue.filter(v => v !== optionValue))\n }, [currentValue, setValue])\n\n const handleOpenChange = React.useCallback((isOpen: boolean) => {\n setOpen(isOpen)\n onOpenChangeProp?.(isOpen)\n if (!isOpen) onBlur?.()\n }, [onBlur, onOpenChangeProp])\n\n const selectableOptions = React.useMemo(\n () => options.filter(o => !o.disabled),\n [options]\n )\n const selectableValues = React.useMemo(\n () => new Set(selectableOptions.map(o => o.value)),\n [selectableOptions]\n )\n const selectedSelectableCount = currentValue.filter(v => selectableValues.has(v)).length\n const allSelected = selectedSelectableCount >= selectableOptions.length && selectableOptions.length > 0\n\n const handleSelectAll = React.useCallback(() => {\n setValue(selectableOptions.map(o => o.value))\n }, [selectableOptions, setValue])\n\n const handleClearAll = React.useCallback(() => {\n setValue([])\n }, [setValue])\n\n const fieldId = `field-${name}`\n const displayedBadges = currentValue.slice(0, maxDisplayedBadges)\n const overflowCount = currentValue.length - displayedBadges.length\n\n if (!isReady) return null;\n\n return (\n <div className={cn(\"flex flex-col gap-item-xs\", className)}>\n <Popover open={open} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <Button\n ref={ref}\n id={fieldId}\n variant={ButtonVariants_Variant.OUTLINE}\n role=\"combobox\"\n aria-expanded={open}\n disabled={disabled || readOnly}\n autoFocus={autoFocus}\n data-size={size}\n /* V-5.c: multi-select uses `min-h-*` (not `h-*`) because the\n trigger grows vertically as chips wrap. We deliberately do\n NOT pass `size` to Button here — Button's recipe uses fixed\n `h-*`, which would clip wrapped chip rows. The recipe's\n focus/disabled/motion still apply via the cn() merge. */\n className={cn(\n \"w-full justify-between font-normal min-h-9\",\n size === \"sm\" && \"min-h-8\",\n currentValue.length === 0 && \"text-muted-foreground\",\n formRecipe.states.focus,\n formRecipe.states.disabled,\n formRecipe.motion.transition,\n )}\n >\n <span className=\"truncate\">\n {currentValue.length === 0\n ? (placeholder ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'selectPlaceholder'))\n : tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'selectedCount', { count: String(currentValue.length) })}\n </span>\n {renderIcon(StandardIconReference.CHEVRONS_UP_DOWN, {\n size: IconSize.SM,\n className: \"ms-2 shrink-0 opacity-[var(--opacity-muted)]\",\n })}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[--radix-popover-trigger-width] p-0\" align={HorizontalAlign.START} surfacePolicyOverride={surfacePolicyOverride}>\n <Command shouldFilter={shouldFilter}>\n <CommandInput\n placeholder={searchPlaceholder ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'searchPlaceholder')}\n onValueChange={onSearchChange}\n />\n <CommandList>\n {/* CommandEmpty is the SOLE loading/empty surface: cmdk renders\n it whenever zero CommandItems exist, and a spinner placed\n inside <CommandGroup> is not an item — it stacks a second\n spinner under this one instead of suppressing it. */}\n <CommandEmpty>\n {isLoading\n ? <LoadingIndicator />\n : (emptyMessage ?? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'noResults'))}\n </CommandEmpty>\n <CommandGroup>\n {showSelectAll && !isLoading && options.length > 0 && (\n <CommandItem\n onSelect={allSelected ? handleClearAll : handleSelectAll}\n className=\"justify-center text-xs text-muted-foreground\"\n >\n {allSelected\n ? tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'clearAll')\n : tComponent(FrontendComponentType.LOW_LEVEL_FORM_FIELD, 'selectAll')}\n </CommandItem>\n )}\n {options.map((option) => {\n const isSelected = selectedSet.has(option.value)\n return (\n <CommandItem\n key={option.value}\n value={option.value}\n keywords={[option.label]}\n disabled={option.disabled}\n onSelect={() => handleToggle(option.value)}\n >\n <div className={cn(\n \"me-2 flex size-4 shrink-0 items-center justify-center rounded-sm border border-primary\",\n isSelected ? \"bg-primary text-primary-foreground\" : \"opacity-[var(--opacity-muted)]\",\n )}>\n {isSelected && renderIcon(StandardIconReference.CHECK, { size: IconSize.XS })}\n </div>\n {renderOption ? renderOption(option, isSelected) : option.label}\n </CommandItem>\n )\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n\n {/*\n * The chip row's gap is `element`: that role's own definition is \"between inline elements\n * (icons, buttons, TAGS)\". It was `item-xs`, and `--sp-item` at a quarter is one pixel, so\n * the chips abutted each other.\n */}\n {currentValue.length > 0 && (\n <div className=\"flex flex-wrap gap-element-sm\">\n {displayedBadges.map((v) => {\n const opt = options.find(o => o.value === v)\n /* No local gap on the chip: `Badge`'s own structure owns the space between its parts. */\n return (\n <Badge key={v} variant=\"secondary\" className=\"pe-1\">\n {opt && renderSelectedValue\n ? renderSelectedValue(opt)\n : (opt?.label ?? v)}\n {!readOnly && !disabled && (\n <button\n type=\"button\"\n aria-label={`Remove ${opt?.label ?? v}`}\n className=\"ms-0.5 rounded-full p-0.5 hover:bg-muted-foreground/20 transition-colors duration-[var(--motion-duration-fast)]\"\n onClick={() => handleRemove(v)}\n >\n {renderIcon(StandardIconReference.X_MARK, { size: IconSize.XS })}\n </button>\n )}\n </Badge>\n )\n })}\n {overflowCount > 0 && (\n <Badge variant=\"secondary\" className=\"text-muted-foreground\">\n +{overflowCount}\n </Badge>\n )}\n </div>\n )}\n </div>\n )\n})\nComboboxMultiple.displayName = \"ComboboxMultiple\"\n\nfunction LoadingIndicator(): React.JSX.Element {\n return (\n <div className=\"flex items-center justify-center py-card-sm\">\n <LoadingSpinner size={16} />\n </div>\n )\n}\n\nexport { Combobox, ComboboxMultiple }\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Places (New) as an address-lookup adapter (#561): what Autocomplete (New) and Place Details (New) take,
|
|
3
|
+
* and how their answers become suggestions and the framework's `AddressValue`.
|
|
4
|
+
*
|
|
5
|
+
* Pure functions over the two backend operations of the `google-places` provider (`address_suggest`,
|
|
6
|
+
* `address_retrieve`); the framework's lookup combobox runs them, and the host fills the session token.
|
|
7
|
+
*
|
|
8
|
+
* ## The address comes from `postalAddress`, never from a formatted string
|
|
9
|
+
*
|
|
10
|
+
* Place Details returns a `google.type.PostalAddress` — CLDR-shaped parts — so no string is parsed back into
|
|
11
|
+
* parts. The mapping onto the framework's address:
|
|
12
|
+
*
|
|
13
|
+
* | `AddressValue` | from `postalAddress` |
|
|
14
|
+
* |---|---|
|
|
15
|
+
* | `line1` | `addressLines[0]` |
|
|
16
|
+
* | `line2` | the remaining `addressLines`, joined with ", " |
|
|
17
|
+
* | `city` | `locality`, else `sublocality` |
|
|
18
|
+
* | `state` | `administrativeArea` |
|
|
19
|
+
* | `postalCode` | `postalCode` |
|
|
20
|
+
* | `country` | `regionCode`, upper-cased (ISO 3166-1 alpha-2) |
|
|
21
|
+
*
|
|
22
|
+
* A place with no street line, no town or no region code is not an address the field can hold (all three are
|
|
23
|
+
* required parts), so `readAddress` answers `undefined` for it: the host says the place cannot be used, fills
|
|
24
|
+
* nothing, and the parts stay as the person left them. What IS filled stays editable, as Google's own guidance for
|
|
25
|
+
* address forms asks: "Leave fields editable in case certain fields are missed from the match".
|
|
26
|
+
* spec-cite: https://developers.google.com/maps/solutions/checkout/best-practices — fetched 2026-09-29.
|
|
27
|
+
*
|
|
28
|
+
* ## Countries
|
|
29
|
+
*
|
|
30
|
+
* A field that accepts at most fifteen countries restricts the search to them (`includedRegionCodes`, which takes
|
|
31
|
+
* at most fifteen). A field that accepts more searches everywhere, and the field's own validation still refuses a
|
|
32
|
+
* country it does not accept.
|
|
33
|
+
*/
|
|
34
|
+
import type { ProviderAddressLookupAdapter } from '@wildo-ai/saas-models';
|
|
35
|
+
/** Thrown when an answer does not have the shape the operation declares — a contract breach, reported through `onError`. */
|
|
36
|
+
export declare class GooglePlacesAnswerUnreadableError extends Error {
|
|
37
|
+
constructor(what: string);
|
|
38
|
+
}
|
|
39
|
+
/** @wildo_source:part:start example.provider.address-lookup.adapter facet:kind:usage-example facet:audience:app-developer */
|
|
40
|
+
export declare const GOOGLE_PLACES_ADDRESS_LOOKUP_ADAPTER: ProviderAddressLookupAdapter;
|
|
41
|
+
/** @wildo_source:part:end example.provider.address-lookup.adapter */
|
|
42
|
+
//# sourceMappingURL=google-places-address-lookup.adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-places-address-lookup.adapter.d.ts","sourceRoot":"","sources":["../../../../../../../../src/components/form/controls/address/providers/google-places-address-lookup.adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAGH,OAAO,KAAK,EAAE,4BAA4B,EAAmC,MAAM,uBAAuB,CAAC;AAK3G,4HAA4H;AAC5H,qBAAa,iCAAkC,SAAQ,KAAK;gBAC9C,IAAI,EAAE,MAAM;CAIzB;AAgBD,6HAA6H;AAC7H,eAAO,MAAM,oCAAoC,EAAE,4BAwDlD,CAAC;AACF,qEAAqE"}
|
package/dist/esm/components/form/controls/address/providers/google-places-address-lookup.adapter.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Places (New) as an address-lookup adapter (#561): what Autocomplete (New) and Place Details (New) take,
|
|
3
|
+
* and how their answers become suggestions and the framework's `AddressValue`.
|
|
4
|
+
*
|
|
5
|
+
* Pure functions over the two backend operations of the `google-places` provider (`address_suggest`,
|
|
6
|
+
* `address_retrieve`); the framework's lookup combobox runs them, and the host fills the session token.
|
|
7
|
+
*
|
|
8
|
+
* ## The address comes from `postalAddress`, never from a formatted string
|
|
9
|
+
*
|
|
10
|
+
* Place Details returns a `google.type.PostalAddress` — CLDR-shaped parts — so no string is parsed back into
|
|
11
|
+
* parts. The mapping onto the framework's address:
|
|
12
|
+
*
|
|
13
|
+
* | `AddressValue` | from `postalAddress` |
|
|
14
|
+
* |---|---|
|
|
15
|
+
* | `line1` | `addressLines[0]` |
|
|
16
|
+
* | `line2` | the remaining `addressLines`, joined with ", " |
|
|
17
|
+
* | `city` | `locality`, else `sublocality` |
|
|
18
|
+
* | `state` | `administrativeArea` |
|
|
19
|
+
* | `postalCode` | `postalCode` |
|
|
20
|
+
* | `country` | `regionCode`, upper-cased (ISO 3166-1 alpha-2) |
|
|
21
|
+
*
|
|
22
|
+
* A place with no street line, no town or no region code is not an address the field can hold (all three are
|
|
23
|
+
* required parts), so `readAddress` answers `undefined` for it: the host says the place cannot be used, fills
|
|
24
|
+
* nothing, and the parts stay as the person left them. What IS filled stays editable, as Google's own guidance for
|
|
25
|
+
* address forms asks: "Leave fields editable in case certain fields are missed from the match".
|
|
26
|
+
* spec-cite: https://developers.google.com/maps/solutions/checkout/best-practices — fetched 2026-09-29.
|
|
27
|
+
*
|
|
28
|
+
* ## Countries
|
|
29
|
+
*
|
|
30
|
+
* A field that accepts at most fifteen countries restricts the search to them (`includedRegionCodes`, which takes
|
|
31
|
+
* at most fifteen). A field that accepts more searches everywhere, and the field's own validation still refuses a
|
|
32
|
+
* country it does not accept.
|
|
33
|
+
*/
|
|
34
|
+
// The provider module's own constant, held equal to the backend operation's limit by the join test (#561).
|
|
35
|
+
import { GOOGLE_PLACES_MAX_INCLUDED_REGION_CODES } from '@wildo-ai/external-connectors-public/app';
|
|
36
|
+
/** Thrown when an answer does not have the shape the operation declares — a contract breach, reported through `onError`. */
|
|
37
|
+
export class GooglePlacesAnswerUnreadableError extends Error {
|
|
38
|
+
constructor(what) {
|
|
39
|
+
super(`Google Places answered a ${what} this lookup cannot read.`);
|
|
40
|
+
this.name = 'GooglePlacesAnswerUnreadableError';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function isRecord(value) {
|
|
44
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
45
|
+
}
|
|
46
|
+
function textOf(value) {
|
|
47
|
+
if (!isRecord(value))
|
|
48
|
+
return undefined;
|
|
49
|
+
const text = value.text;
|
|
50
|
+
return typeof text === 'string' && text.trim() !== '' ? text : undefined;
|
|
51
|
+
}
|
|
52
|
+
function nonEmpty(value) {
|
|
53
|
+
return typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined;
|
|
54
|
+
}
|
|
55
|
+
/** @wildo_source:part:start example.provider.address-lookup.adapter facet:kind:usage-example facet:audience:app-developer */
|
|
56
|
+
export const GOOGLE_PLACES_ADDRESS_LOOKUP_ADAPTER = {
|
|
57
|
+
buildSuggestInput({ query, countriesAllowed, languageCode }) {
|
|
58
|
+
const regions = countriesAllowed !== undefined && countriesAllowed.length > 0 && countriesAllowed.length <= GOOGLE_PLACES_MAX_INCLUDED_REGION_CODES
|
|
59
|
+
? countriesAllowed.map((code) => code.toLowerCase())
|
|
60
|
+
: undefined;
|
|
61
|
+
return {
|
|
62
|
+
input: query,
|
|
63
|
+
languageCode,
|
|
64
|
+
...(regions !== undefined ? { includedRegionCodes: regions } : {}),
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
readSuggestions(output) {
|
|
68
|
+
if (!isRecord(output))
|
|
69
|
+
throw new GooglePlacesAnswerUnreadableError('suggestion list');
|
|
70
|
+
const raw = output.suggestions;
|
|
71
|
+
if (raw === undefined)
|
|
72
|
+
return [];
|
|
73
|
+
if (!Array.isArray(raw))
|
|
74
|
+
throw new GooglePlacesAnswerUnreadableError('suggestion list');
|
|
75
|
+
const suggestions = [];
|
|
76
|
+
for (const entry of raw) {
|
|
77
|
+
// A `queryPrediction` (a search phrase rather than a place) is not requested and cannot be retrieved: skipped.
|
|
78
|
+
const prediction = isRecord(entry) ? entry.placePrediction : undefined;
|
|
79
|
+
if (!isRecord(prediction) || typeof prediction.placeId !== 'string' || prediction.placeId === '')
|
|
80
|
+
continue;
|
|
81
|
+
const structured = isRecord(prediction.structuredFormat) ? prediction.structuredFormat : undefined;
|
|
82
|
+
const primaryText = textOf(structured?.mainText) ?? textOf(prediction.text);
|
|
83
|
+
if (primaryText === undefined)
|
|
84
|
+
continue;
|
|
85
|
+
const secondaryText = textOf(structured?.secondaryText);
|
|
86
|
+
suggestions.push({ id: prediction.placeId, primaryText, ...(secondaryText !== undefined ? { secondaryText } : {}) });
|
|
87
|
+
}
|
|
88
|
+
return suggestions;
|
|
89
|
+
},
|
|
90
|
+
buildRetrieveInput({ suggestion, languageCode }) {
|
|
91
|
+
return { placeId: suggestion.id, languageCode };
|
|
92
|
+
},
|
|
93
|
+
readAddress(output) {
|
|
94
|
+
if (!isRecord(output))
|
|
95
|
+
throw new GooglePlacesAnswerUnreadableError('place');
|
|
96
|
+
const postal = output.postalAddress;
|
|
97
|
+
if (postal === undefined)
|
|
98
|
+
return undefined;
|
|
99
|
+
if (!isRecord(postal))
|
|
100
|
+
throw new GooglePlacesAnswerUnreadableError('postal address');
|
|
101
|
+
const lines = Array.isArray(postal.addressLines) ? postal.addressLines.map(nonEmpty).filter((line) => line !== undefined) : [];
|
|
102
|
+
const country = nonEmpty(postal.regionCode)?.toUpperCase();
|
|
103
|
+
const [line1, ...rest] = lines;
|
|
104
|
+
const city = nonEmpty(postal.locality) ?? nonEmpty(postal.sublocality);
|
|
105
|
+
if (line1 === undefined || city === undefined || country === undefined)
|
|
106
|
+
return undefined;
|
|
107
|
+
const state = nonEmpty(postal.administrativeArea);
|
|
108
|
+
const postalCode = nonEmpty(postal.postalCode);
|
|
109
|
+
return {
|
|
110
|
+
line1,
|
|
111
|
+
...(rest.length > 0 ? { line2: rest.join(', ') } : {}),
|
|
112
|
+
city,
|
|
113
|
+
...(state !== undefined ? { state } : {}),
|
|
114
|
+
...(postalCode !== undefined ? { postalCode } : {}),
|
|
115
|
+
country,
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
/** @wildo_source:part:end example.provider.address-lookup.adapter */
|
|
120
|
+
//# sourceMappingURL=google-places-address-lookup.adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-places-address-lookup.adapter.js","sourceRoot":"","sources":["../../../../../../../../src/components/form/controls/address/providers/google-places-address-lookup.adapter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Google Places (New) as an address-lookup adapter (#561): what Autocomplete (New) and Place Details (New) take,\n * and how their answers become suggestions and the framework's `AddressValue`.\n *\n * Pure functions over the two backend operations of the `google-places` provider (`address_suggest`,\n * `address_retrieve`); the framework's lookup combobox runs them, and the host fills the session token.\n *\n * ## The address comes from `postalAddress`, never from a formatted string\n *\n * Place Details returns a `google.type.PostalAddress` — CLDR-shaped parts — so no string is parsed back into\n * parts. The mapping onto the framework's address:\n *\n * | `AddressValue` | from `postalAddress` |\n * |---|---|\n * | `line1` | `addressLines[0]` |\n * | `line2` | the remaining `addressLines`, joined with \", \" |\n * | `city` | `locality`, else `sublocality` |\n * | `state` | `administrativeArea` |\n * | `postalCode` | `postalCode` |\n * | `country` | `regionCode`, upper-cased (ISO 3166-1 alpha-2) |\n *\n * A place with no street line, no town or no region code is not an address the field can hold (all three are\n * required parts), so `readAddress` answers `undefined` for it: the host says the place cannot be used, fills\n * nothing, and the parts stay as the person left them. What IS filled stays editable, as Google's own guidance for\n * address forms asks: \"Leave fields editable in case certain fields are missed from the match\".\n * spec-cite: https://developers.google.com/maps/solutions/checkout/best-practices — fetched 2026-09-29.\n *\n * ## Countries\n *\n * A field that accepts at most fifteen countries restricts the search to them (`includedRegionCodes`, which takes\n * at most fifteen). A field that accepts more searches everywhere, and the field's own validation still refuses a\n * country it does not accept.\n */\n\nimport type { AddressValue } from '@wildo-ai/zod-decorators';\nimport type { ProviderAddressLookupAdapter, ProviderAddressLookupSuggestion } from '@wildo-ai/saas-models';\n// The provider module's own constant, held equal to the backend operation's limit by the join test (#561).\nimport { GOOGLE_PLACES_MAX_INCLUDED_REGION_CODES } from '@wildo-ai/external-connectors-public/app';\n\n\n/** Thrown when an answer does not have the shape the operation declares — a contract breach, reported through `onError`. */\nexport class GooglePlacesAnswerUnreadableError extends Error {\n constructor(what: string) {\n super(`Google Places answered a ${what} this lookup cannot read.`);\n this.name = 'GooglePlacesAnswerUnreadableError';\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction textOf(value: unknown): string | undefined {\n if (!isRecord(value)) return undefined;\n const text = value.text;\n return typeof text === 'string' && text.trim() !== '' ? text : undefined;\n}\n\nfunction nonEmpty(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined;\n}\n\n/** @wildo_source:part:start example.provider.address-lookup.adapter facet:kind:usage-example facet:audience:app-developer */\nexport const GOOGLE_PLACES_ADDRESS_LOOKUP_ADAPTER: ProviderAddressLookupAdapter = {\n buildSuggestInput({ query, countriesAllowed, languageCode }) {\n const regions = countriesAllowed !== undefined && countriesAllowed.length > 0 && countriesAllowed.length <= GOOGLE_PLACES_MAX_INCLUDED_REGION_CODES\n ? countriesAllowed.map((code) => code.toLowerCase())\n : undefined;\n return {\n input: query,\n languageCode,\n ...(regions !== undefined ? { includedRegionCodes: regions } : {}),\n };\n },\n\n readSuggestions(output) {\n if (!isRecord(output)) throw new GooglePlacesAnswerUnreadableError('suggestion list');\n const raw = output.suggestions;\n if (raw === undefined) return [];\n if (!Array.isArray(raw)) throw new GooglePlacesAnswerUnreadableError('suggestion list');\n const suggestions: ProviderAddressLookupSuggestion[] = [];\n for (const entry of raw) {\n // A `queryPrediction` (a search phrase rather than a place) is not requested and cannot be retrieved: skipped.\n const prediction = isRecord(entry) ? entry.placePrediction : undefined;\n if (!isRecord(prediction) || typeof prediction.placeId !== 'string' || prediction.placeId === '') continue;\n const structured = isRecord(prediction.structuredFormat) ? prediction.structuredFormat : undefined;\n const primaryText = textOf(structured?.mainText) ?? textOf(prediction.text);\n if (primaryText === undefined) continue;\n const secondaryText = textOf(structured?.secondaryText);\n suggestions.push({ id: prediction.placeId, primaryText, ...(secondaryText !== undefined ? { secondaryText } : {}) });\n }\n return suggestions;\n },\n\n buildRetrieveInput({ suggestion, languageCode }) {\n return { placeId: suggestion.id, languageCode };\n },\n\n readAddress(output): AddressValue | undefined {\n if (!isRecord(output)) throw new GooglePlacesAnswerUnreadableError('place');\n const postal = output.postalAddress;\n if (postal === undefined) return undefined;\n if (!isRecord(postal)) throw new GooglePlacesAnswerUnreadableError('postal address');\n const lines = Array.isArray(postal.addressLines) ? postal.addressLines.map(nonEmpty).filter((line): line is string => line !== undefined) : [];\n const country = nonEmpty(postal.regionCode)?.toUpperCase();\n const [line1, ...rest] = lines;\n const city = nonEmpty(postal.locality) ?? nonEmpty(postal.sublocality);\n if (line1 === undefined || city === undefined || country === undefined) return undefined;\n const state = nonEmpty(postal.administrativeArea);\n const postalCode = nonEmpty(postal.postalCode);\n return {\n line1,\n ...(rest.length > 0 ? { line2: rest.join(', ') } : {}),\n city,\n ...(state !== undefined ? { state } : {}),\n ...(postalCode !== undefined ? { postalCode } : {}),\n country,\n };\n },\n};\n/** @wildo_source:part:end example.provider.address-lookup.adapter */\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GooglePlacesAddressLookup — the `FRONTEND_ADDRESS_LOOKUP` component the `google-places` provider declares (#561).
|
|
3
|
+
*
|
|
4
|
+
* Nothing but the framework's lookup combobox with Google's adapter: the keyboard pattern, debounce, minimum query
|
|
5
|
+
* length and failure reporting are the framework's (`ProviderAddressLookupCombobox`), the session token and the
|
|
6
|
+
* attribution are the host's, and what is Google's — the request shapes and the answer mapping — is
|
|
7
|
+
* `GOOGLE_PLACES_ADDRESS_LOOKUP_ADAPTER`. No Google code, script or key ever reaches the page: both calls run on
|
|
8
|
+
* the application backend through the provider-operation door.
|
|
9
|
+
*
|
|
10
|
+
* Not behind a lazy door, unlike the file pickers: those load a vendor SDK when opened, while this adds a few
|
|
11
|
+
* pure functions to a combobox the application already ships, so a split point would cost a request and save nothing.
|
|
12
|
+
*/
|
|
13
|
+
import * as React from "react";
|
|
14
|
+
import type { ProviderAddressLookupProps } from "@wildo-ai/saas-models";
|
|
15
|
+
export declare function GooglePlacesAddressLookup(props: ProviderAddressLookupProps): React.JSX.Element;
|
|
16
|
+
//# sourceMappingURL=google-places-address-lookup.d.ts.map
|
package/dist/esm/components/form/controls/address/providers/google-places-address-lookup.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-places-address-lookup.d.ts","sourceRoot":"","sources":["../../../../../../../../src/components/form/controls/address/providers/google-places-address-lookup.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAA;AAIvE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,0BAA0B,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAE9F"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { ProviderAddressLookupCombobox } from "@wildo-ai/saas-frontend-lib";
|
|
4
|
+
import { GOOGLE_PLACES_ADDRESS_LOOKUP_ADAPTER } from "./google-places-address-lookup.adapter.js";
|
|
5
|
+
export function GooglePlacesAddressLookup(props) {
|
|
6
|
+
return _jsx(ProviderAddressLookupCombobox, { ...props, adapter: GOOGLE_PLACES_ADDRESS_LOOKUP_ADAPTER });
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=google-places-address-lookup.js.map
|
package/dist/esm/components/form/controls/address/providers/google-places-address-lookup.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-places-address-lookup.js","sourceRoot":"","sources":["../../../../../../../../src/components/form/controls/address/providers/google-places-address-lookup.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAiBZ,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAA;AAC3E,OAAO,EAAE,oCAAoC,EAAE,MAAM,wCAAwC,CAAA;AAE7F,MAAM,UAAU,yBAAyB,CAAC,KAAiC;IACzE,OAAO,KAAC,6BAA6B,OAAK,KAAK,EAAE,OAAO,EAAE,oCAAoC,GAAI,CAAA;AACpG,CAAC","sourcesContent":["\"use client\"\n\n/**\n * GooglePlacesAddressLookup — the `FRONTEND_ADDRESS_LOOKUP` component the `google-places` provider declares (#561).\n *\n * Nothing but the framework's lookup combobox with Google's adapter: the keyboard pattern, debounce, minimum query\n * length and failure reporting are the framework's (`ProviderAddressLookupCombobox`), the session token and the\n * attribution are the host's, and what is Google's — the request shapes and the answer mapping — is\n * `GOOGLE_PLACES_ADDRESS_LOOKUP_ADAPTER`. No Google code, script or key ever reaches the page: both calls run on\n * the application backend through the provider-operation door.\n *\n * Not behind a lazy door, unlike the file pickers: those load a vendor SDK when opened, while this adds a few\n * pure functions to a combobox the application already ships, so a split point would cost a request and save nothing.\n */\n\nimport * as React from \"react\"\nimport type { ProviderAddressLookupProps } from \"@wildo-ai/saas-models\"\nimport { ProviderAddressLookupCombobox } from \"@wildo-ai/saas-frontend-lib\"\nimport { GOOGLE_PLACES_ADDRESS_LOOKUP_ADAPTER } from \"./google-places-address-lookup.adapter\"\n\nexport function GooglePlacesAddressLookup(props: ProviderAddressLookupProps): React.JSX.Element {\n return <ProviderAddressLookupCombobox {...props} adapter={GOOGLE_PLACES_ADDRESS_LOOKUP_ADAPTER} />\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-bar.d.ts","sourceRoot":"","sources":["../../../../../../src/components/navigation/app-level/activity-bar.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,EAcL,iCAAiC,EAClC,MAAM,6BAA6B,CAAC;AAKrC,eAAO,MAAM,0CAA0C,EAAE,KAAK,CAAC,EAAE,CAAC,iCAAiC,
|
|
1
|
+
{"version":3,"file":"activity-bar.d.ts","sourceRoot":"","sources":["../../../../../../src/components/navigation/app-level/activity-bar.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,EAcL,iCAAiC,EAClC,MAAM,6BAA6B,CAAC;AAKrC,eAAO,MAAM,0CAA0C,EAAE,KAAK,CAAC,EAAE,CAAC,iCAAiC,CAmFlG,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ButtonSize, FrontendComponentType, PlacementSide, ShellAppearance, SurfaceVariant } from '@wildo-ai/presets-components-models';
|
|
2
|
+
import { ButtonSize, FrontendComponentType, PlacementSide, ShellAppearance, ShellRegion, SurfaceVariant } from '@wildo-ai/presets-components-models';
|
|
3
3
|
import { LayoutDirection } from '@wildo-ai/zod-decorators';
|
|
4
4
|
import { Button, ButtonVariants_Variant, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, useI18n, useIconRegistry, useActivityBarBehavior, useUI, IconSize, cn, Surface, } from '@wildo-ai/saas-frontend-lib';
|
|
5
5
|
const TOOLTIP_DELAY_MS = 100;
|
|
@@ -25,7 +25,7 @@ export const ApplicationLevelPreset_ActivityBar_Default = () => {
|
|
|
25
25
|
return null;
|
|
26
26
|
return (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.SUNKEN, children: _jsx("div", { className: cn('flex', isContinuousShell
|
|
27
27
|
? 'bg-transparent text-foreground'
|
|
28
|
-
: cn('bg-surface-sunken text-surface-sunken-foreground border-surface-sunken-border', borderClass), isVertical ? 'w-16 flex-col items-center py-card' : 'h-14 flex-row items-center px-card'), "data-component-type": "activity-bar", "data-rendering-mode": behavior.activeRenderingMode, children: _jsx(TooltipProvider, { delayDuration: TOOLTIP_DELAY_MS, children: _jsx("nav", { "aria-label": tComponent(FrontendComponentType.APPLICATION_LEVEL_ACTIVITY_BAR, 'modeLabel'), className: cn('flex items-center gap-element', isVertical ? 'flex-col' : 'flex-row', isVertical ? 'w-full px-card-sm' : 'h-full py-card-sm'), role: "radiogroup", "aria-orientation": layout.orientation, children: availableModes.map((mode) => {
|
|
28
|
+
: cn('bg-surface-sunken text-surface-sunken-foreground border-surface-sunken-border', borderClass), isVertical ? 'w-16 flex-col items-center py-card' : 'h-14 flex-row items-center px-card'), "data-component-area": ShellRegion.ACTIVITY_BAR, "data-component-type": "activity-bar", "data-rendering-mode": behavior.activeRenderingMode, children: _jsx(TooltipProvider, { delayDuration: TOOLTIP_DELAY_MS, children: _jsx("nav", { "aria-label": tComponent(FrontendComponentType.APPLICATION_LEVEL_ACTIVITY_BAR, 'modeLabel'), className: cn('flex items-center gap-element', isVertical ? 'flex-col' : 'flex-row', isVertical ? 'w-full px-card-sm' : 'h-full py-card-sm'), role: "radiogroup", "aria-orientation": layout.orientation, children: availableModes.map((mode) => {
|
|
29
29
|
const isActive = activeMode === mode.ref;
|
|
30
30
|
const modeIcon = renderIcon(mode.icon, { size: IconSize.SM });
|
|
31
31
|
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { variant: ButtonVariants_Variant.GHOST, size: ButtonSize.ICON, onClick: () => setActiveMode(mode.ref), "aria-checked": isActive, role: "radio", className: cn(TILE_SIZE_CLASS, isActive && 'bg-primary/10 text-primary hover:bg-primary/15'), "aria-label": mode.label, children: modeIcon || (_jsx("span", { className: "text-lg", children: mode.label.charAt(0).toUpperCase() })) }) }), _jsx(TooltipContent, { side: layout.tooltipSide, children: _jsx("p", { children: mode.label }) })] }, mode.ref));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-bar.js","sourceRoot":"","sources":["../../../../../../src/components/navigation/app-level/activity-bar.tsx"],"names":[],"mappings":";AAeA,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"activity-bar.js","sourceRoot":"","sources":["../../../../../../src/components/navigation/app-level/activity-bar.tsx"],"names":[],"mappings":";AAeA,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACrJ,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE3D,OAAO,EACL,MAAM,EACN,sBAAsB,EACtB,OAAO,EACP,cAAc,EACd,eAAe,EACf,cAAc,EACd,OAAO,EACP,eAAe,EACf,sBAAsB,EACtB,KAAK,EACL,QAAQ,EACR,EAAE,EACF,OAAO,GAER,MAAM,6BAA6B,CAAC;AAErC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,eAAe,GAAG,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,0CAA0C,GAAgD,GAAG,EAAE;IAC1G,MAAM,QAAQ,GAAG,sBAAsB,EAAE,CAAC;IAC1C,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACtC,SAAS,EAAE,qBAAqB,CAAC,8BAA8B;KAChE,CAAC,CAAC;IACH,MAAM,EAAE,UAAU,EAAE,GAAG,eAAe,EAAE,CAAC;IACzC,MAAM,EAAE,eAAe,EAAE,GAAG,KAAK,EAAE,CAAC;IACpC,oEAAoE;IACpE,MAAM,iBAAiB,GAAG,eAAe,KAAK,eAAe,CAAC,UAAU,CAAC;IAEzE,IAAI,CAAC,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,QAAQ,CAAC;IACvE,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,KAAK,eAAe,CAAC,QAAQ,CAAC;IAEjE,MAAM,WAAW,GAAG,MAAM,CAAC,UAAU,KAAK,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU;QACtE,CAAC,CAAC,MAAM,CAAC,UAAU,KAAK,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU;YACzD,CAAC,CAAC,UAAU,CAAC;IAEf,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,OAAO,CACL,KAAC,OAAO,IAAC,OAAO,QAAC,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,MAAM,YACpE,cACE,SAAS,EAAE,EAAE,CACX,MAAM,EACN,iBAAiB;gBACf,CAAC,CAAC,gCAAgC;gBAClC,CAAC,CAAC,EAAE,CAAC,+EAA+E,EAAE,WAAW,CAAC,EACpG,UAAU,CAAC,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC,oCAAoC,CACzF,yBACoB,WAAW,CAAC,YAAY,yBACzB,cAAc,yBACb,QAAQ,CAAC,mBAAmB,YAEjD,KAAC,eAAe,IAAC,aAAa,EAAE,gBAAgB,YAC9C,4BACc,UAAU,CAAC,qBAAqB,CAAC,8BAA8B,EAAE,WAAW,CAAC,EACzF,SAAS,EAAE,EAAE,CACX,+BAA+B,EAC/B,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,EACpC,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,mBAAmB,CACvD,EACD,IAAI,EAAC,YAAY,sBACC,MAAM,CAAC,WAAW,YAEnC,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;wBAC3B,MAAM,QAAQ,GAAG,UAAU,KAAK,IAAI,CAAC,GAAG,CAAC;wBACzC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;wBAE9D,OAAO,CACL,MAAC,OAAO,eACN,KAAC,cAAc,IAAC,OAAO,kBACrB,KAAC,MAAM,IACL,OAAO,EAAE,sBAAsB,CAAC,KAAK,EACrC,IAAI,EAAE,UAAU,CAAC,IAAI,EACrB,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,kBACxB,QAAQ,EACtB,IAAI,EAAC,OAAO,EACZ,SAAS,EAAE,EAAE,CACX,eAAe,EACf,QAAQ,IAAI,gDAAgD,CAC7D,gBACW,IAAI,CAAC,KAAK,YAErB,QAAQ,IAAI,CACX,eAAM,SAAS,EAAC,SAAS,YAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAQ,CACtE,GACM,GACM,EACjB,KAAC,cAAc,IAAC,IAAI,EAAE,MAAM,CAAC,WAAW,YACtC,sBAAI,IAAI,CAAC,KAAK,GAAK,GACJ,KArBL,IAAI,CAAC,GAAG,CAsBZ,CACX,CAAC;oBACJ,CAAC,CAAC,GACE,GACU,GACd,GACE,CACX,CAAC;AACJ,CAAC,CAAC","sourcesContent":["/**\n * Activity Bar — Default Preset\n *\n * Mode selector that renders available AppModes as selectable icons.\n * Consumes `useAppMode()` for mode state and `useI18n()` for labels.\n *\n * Renders as a vertical icon column (VERTICAL_RAIL) by default.\n * When no modes are configured, this component renders nothing.\n *\n * @see component-taxonomy-deep-review.md §3.5.2, §5\n * @see app-shell-implementation-plan.md Step 7a\n */\n\nimport React from 'react';\n\nimport { ButtonSize, FrontendComponentType, PlacementSide, ShellAppearance, ShellRegion, SurfaceVariant } from '@wildo-ai/presets-components-models';\nimport { LayoutDirection } from '@wildo-ai/zod-decorators';\n\nimport {\n Button,\n ButtonVariants_Variant,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n useI18n,\n useIconRegistry,\n useActivityBarBehavior,\n useUI,\n IconSize,\n cn,\n Surface,\n ApplicationLevelProps_ActivityBar,\n} from '@wildo-ai/saas-frontend-lib';\n\nconst TOOLTIP_DELAY_MS = 100;\nconst TILE_SIZE_CLASS = 'w-12 h-12';\n\nexport const ApplicationLevelPreset_ActivityBar_Default: React.FC<ApplicationLevelProps_ActivityBar> = () => {\n const behavior = useActivityBarBehavior();\n const { tComponent, isReady } = useI18n({\n component: FrontendComponentType.APPLICATION_LEVEL_ACTIVITY_BAR,\n });\n const { renderIcon } = useIconRegistry();\n const { shellAppearance } = useUI();\n // CONTINUOUS shell chrome: transparent strip, no separating border.\n const isContinuousShell = shellAppearance === ShellAppearance.CONTINUOUS;\n\n if (!behavior.hasModes || behavior.availableModes.length === 0) {\n return null;\n }\n\n const { layout, availableModes, activeMode, setActiveMode } = behavior;\n const isVertical = layout.direction === LayoutDirection.VERTICAL;\n\n const borderClass = layout.borderSide === PlacementSide.END ? 'border-e'\n : layout.borderSide === PlacementSide.BOTTOM ? 'border-b'\n : 'border-t';\n\n if (!isReady) return null;\n\n return (\n <Surface asChild emitPolicyVars={false} variant={SurfaceVariant.SUNKEN}>\n <div\n className={cn(\n 'flex',\n isContinuousShell\n ? 'bg-transparent text-foreground'\n : cn('bg-surface-sunken text-surface-sunken-foreground border-surface-sunken-border', borderClass),\n isVertical ? 'w-16 flex-col items-center py-card' : 'h-14 flex-row items-center px-card',\n )}\n data-component-area={ShellRegion.ACTIVITY_BAR}\n data-component-type=\"activity-bar\"\n data-rendering-mode={behavior.activeRenderingMode}\n >\n <TooltipProvider delayDuration={TOOLTIP_DELAY_MS}>\n <nav\n aria-label={tComponent(FrontendComponentType.APPLICATION_LEVEL_ACTIVITY_BAR, 'modeLabel')}\n className={cn(\n 'flex items-center gap-element',\n isVertical ? 'flex-col' : 'flex-row',\n isVertical ? 'w-full px-card-sm' : 'h-full py-card-sm',\n )}\n role=\"radiogroup\"\n aria-orientation={layout.orientation}\n >\n {availableModes.map((mode) => {\n const isActive = activeMode === mode.ref;\n const modeIcon = renderIcon(mode.icon, { size: IconSize.SM });\n\n return (\n <Tooltip key={mode.ref}>\n <TooltipTrigger asChild>\n <Button\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.ICON}\n onClick={() => setActiveMode(mode.ref)}\n aria-checked={isActive}\n role=\"radio\"\n className={cn(\n TILE_SIZE_CLASS,\n isActive && 'bg-primary/10 text-primary hover:bg-primary/15',\n )}\n aria-label={mode.label}\n >\n {modeIcon || (\n <span className=\"text-lg\">{mode.label.charAt(0).toUpperCase()}</span>\n )}\n </Button>\n </TooltipTrigger>\n <TooltipContent side={layout.tooltipSide}>\n <p>{mode.label}</p>\n </TooltipContent>\n </Tooltip>\n );\n })}\n </nav>\n </TooltipProvider>\n </div>\n </Surface>\n );\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-user-org.d.ts","sourceRoot":"","sources":["../../../../../../src/components/navigation/app-level/menu-user-org.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsB,MAAM,OAAO,CAAC;AAoB3C,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,6BAA6B,CAAC;AAErF,eAAO,MAAM,0CAA0C,EAAE,KAAK,CAAC,EAAE,CAAC,iCAAiC,
|
|
1
|
+
{"version":3,"file":"menu-user-org.d.ts","sourceRoot":"","sources":["../../../../../../src/components/navigation/app-level/menu-user-org.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsB,MAAM,OAAO,CAAC;AAoB3C,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,6BAA6B,CAAC;AAErF,eAAO,MAAM,0CAA0C,EAAE,KAAK,CAAC,EAAE,CAAC,iCAAiC,CA2UlG,CAAC"}
|
|
@@ -35,13 +35,19 @@ export const ApplicationLevelPreset_MenuUserOrg_Default = ({ containerType, cont
|
|
|
35
35
|
return null;
|
|
36
36
|
const hasMultipleOrgs = organizations && organizations.length > 1;
|
|
37
37
|
const orgsLabel = tc('organizations');
|
|
38
|
+
const ownOrganizations = (organizations ?? []).filter(org => !org.viaProviderOrganizationName);
|
|
39
|
+
const clientOrganizations = (organizations ?? []).filter(org => Boolean(org.viaProviderOrganizationName));
|
|
40
|
+
const orgGroups = [
|
|
41
|
+
{ key: 'own', label: orgsLabel, organizations: ownOrganizations },
|
|
42
|
+
{ key: 'clients', label: tc('clientOrganizations'), organizations: clientOrganizations },
|
|
43
|
+
].filter(group => group.organizations.length > 0);
|
|
38
44
|
const checkIcon = renderIcon(StandardIconReference.CHECK, { size: IconSize.SM });
|
|
39
45
|
return (_jsxs(_Fragment, { children: [_jsx(Separator, {}), hasMultipleOrgs && showOrgSwitcher && sections.includes(UserDropdownSection.ORG_SWITCHER) ? (
|
|
40
46
|
/* Multiple orgs — full selectable list */
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
_jsx("div", { className: "p-item", children: orgGroups.map(group => (_jsxs("div", { className: cn(group.key === 'clients' && 'mt-item'), children: [_jsx("p", { className: "text-xs text-muted-foreground mb-item px-card-sm", children: group.label }), _jsx("div", { className: "space-y-item-xs", children: group.organizations.map(org => {
|
|
48
|
+
const isSelected = org._id === currentOrganization?._id;
|
|
49
|
+
return (_jsxs(Button, { "data-component-type": "user-org-menu-option", "data-organization-id": org._id, "data-selected": isSelected ? 'true' : 'false', variant: ButtonVariants_Variant.GHOST, size: ButtonSize.SM, onClick: () => handleSwitchOrg(org._id), className: cn('w-full justify-start text-sm rounded-sm', isSelected && 'bg-primary/10 text-primary hover:bg-primary/15'), children: [_jsx("span", { className: cn('flex-shrink-0', isSelected ? 'text-primary' : 'invisible'), children: checkIcon }), _jsxs("span", { className: "flex min-w-0 flex-col items-start", children: [_jsx("span", { className: "truncate", children: org.name }), org.viaProviderOrganizationName ? (_jsx("span", { className: "truncate text-xs text-muted-foreground", children: tComponent(FrontendComponentType.APPLICATION_LEVEL_USER_DROPDOWN, 'servedViaFirm', { firm: org.viaProviderOrganizationName }) })) : null] })] }, org._id));
|
|
50
|
+
}) })] }, group.key))) })) : (
|
|
45
51
|
/* Single org — non-interactive display */
|
|
46
52
|
_jsxs("div", { className: "px-card py-card-sm", children: [_jsx("p", { className: "text-xs text-muted-foreground leading-none", children: orgsLabel }), _jsx("p", { className: "text-sm font-medium leading-none mt-element truncate", children: currentOrganization?.name ?? '' })] }))] }));
|
|
47
53
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-user-org.js","sourceRoot":"","sources":["../../../../../../src/components/navigation/app-level/menu-user-org.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useCallback } from 'react';\nimport {\n UserDropdownSection,\n UserDropdownAvatarDisplay,\n} from '@wildo-ai/saas-frontend-lib';\n\nimport { ButtonSize, FrontendComponentType } from '@wildo-ai/presets-components-models';\n\nimport {\n DropdownMenu, DropdownMenuContent, DropdownMenuTrigger,\n Avatar, AvatarFallback, AvatarImage,\n Button, ButtonVariants_Variant,\n Separator,\n useI18n,\n useIconRegistry,\n useMenuUserOrgBehavior,\n IconSize, StandardIconReference,\n cn,\n} from '@wildo-ai/saas-frontend-lib';\n\nimport type { ApplicationLevelProps_MenuUserOrg } from '@wildo-ai/saas-frontend-lib';\n\nexport const ApplicationLevelPreset_MenuUserOrg_Default: React.FC<ApplicationLevelProps_MenuUserOrg> = ({\n containerType,\n containerPlacement,\n}) => {\n const behavior = useMenuUserOrgBehavior(containerType, containerPlacement);\n const { tComponent, isReady } = useI18n({ component: FrontendComponentType.APPLICATION_LEVEL_USER_DROPDOWN });\n const { renderIcon } = useIconRegistry();\n\n const {\n isOpen,\n setIsOpen,\n isUserAuthenticated,\n userInitials,\n displayName,\n email,\n avatarUrl,\n currentOrganization,\n organizations,\n sections,\n avatarDisplay,\n showOrgSwitcher,\n showLogout,\n settingsTarget,\n settingsTargets,\n popupAlignment,\n handleLogout,\n handleSwitchOrg,\n handleNavigateToSettingsTarget,\n } = behavior;\n\n const tc = useCallback(\n (key: string) => tComponent(FrontendComponentType.APPLICATION_LEVEL_USER_DROPDOWN, key),\n [tComponent],\n );\n\n // ===================================================================\n // Render Helpers\n // ===================================================================\n\n const renderTriggerContent = () => {\n\n switch (avatarDisplay) {\n case UserDropdownAvatarDisplay.AVATAR_NAME:\n return (\n <div className=\"flex items-center gap-element\">\n <Avatar className=\"h-8 w-8\">\n <AvatarImage src={avatarUrl} alt={displayName} />\n <AvatarFallback className=\"text-xs\">{userInitials}</AvatarFallback>\n </Avatar>\n <span className=\"text-sm font-medium max-w-[120px] truncate\">{displayName}</span>\n </div>\n );\n case UserDropdownAvatarDisplay.AVATAR_ORG:\n return (\n <div className=\"flex items-center gap-element\">\n <Avatar className=\"h-8 w-8\">\n <AvatarImage src={avatarUrl} alt={displayName} />\n <AvatarFallback className=\"text-xs\">{userInitials}</AvatarFallback>\n </Avatar>\n <span className=\"text-sm font-medium max-w-[120px] truncate\">\n {currentOrganization?.name ?? displayName}\n </span>\n </div>\n );\n case UserDropdownAvatarDisplay.FULL:\n return (\n <div className=\"flex items-center gap-element\">\n <Avatar className=\"h-8 w-8\">\n <AvatarImage src={avatarUrl} alt={displayName} />\n <AvatarFallback className=\"text-xs\">{userInitials}</AvatarFallback>\n </Avatar>\n <div className=\"flex flex-col items-start\">\n <span className=\"text-sm font-medium max-w-[120px] truncate\">{displayName}</span>\n <span className=\"text-xs text-muted-foreground max-w-[120px] truncate\">\n {currentOrganization?.name}\n </span>\n </div>\n </div>\n );\n case UserDropdownAvatarDisplay.AVATAR_ONLY:\n default:\n return (\n <Avatar className=\"h-8 w-8\">\n <AvatarImage src={avatarUrl} alt={displayName} />\n <AvatarFallback className=\"text-xs\">{userInitials}</AvatarFallback>\n </Avatar>\n );\n }\n };\n\n const renderUserInfoSection = () => {\n if (!sections.includes(UserDropdownSection.USER_INFO)) return null;\n\n return (\n <div className=\"px-card py-card-sm\">\n <p className=\"text-sm font-medium leading-none truncate\">{displayName}</p>\n <p className=\"text-xs leading-none text-muted-foreground mt-item truncate\">{email}</p>\n </div>\n );\n };\n\n const renderOrgSection = () => {\n if (!sections.includes(UserDropdownSection.ORG_SWITCHER)) return null;\n\n const hasMultipleOrgs = organizations && organizations.length > 1;\n const orgsLabel = tc('organizations');\n\n const checkIcon = renderIcon(\n StandardIconReference.CHECK,\n { size: IconSize.SM }\n );\n\n return (\n <>\n <Separator />\n\n {hasMultipleOrgs && showOrgSwitcher && sections.includes(UserDropdownSection.ORG_SWITCHER) ? (\n /* Multiple orgs — full selectable list */\n <div className=\"p-item\">\n <p className=\"text-xs text-muted-foreground mb-item px-card-sm\">{orgsLabel}</p>\n <div className=\"space-y-item-xs\">\n {organizations.map(org => {\n const isSelected = org._id === currentOrganization?._id;\n return (\n <Button\n key={org._id}\n /*\n * The org's IDENTITY on the element, not its name: a scenario asserting which\n * organization is active must not have to match a display name it did not choose,\n * and `data-selected` states the current one without reading the check icon —\n * which is an icon, and therefore not assertable text at all.\n */\n data-component-type=\"user-org-menu-option\"\n data-organization-id={org._id}\n data-selected={isSelected ? 'true' : 'false'}\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n onClick={() => handleSwitchOrg(org._id)}\n className={cn('w-full justify-start text-sm rounded-sm', isSelected && 'bg-primary/10 text-primary hover:bg-primary/15')}\n >\n <span className={cn('flex-shrink-0', isSelected ? 'text-primary' : 'invisible')}>\n {checkIcon}\n </span>\n <span className=\"truncate\">{org.name}</span>\n </Button>\n );\n })}\n </div>\n </div>\n ) : (\n /* Single org — non-interactive display */\n <div className=\"px-card py-card-sm\">\n <p className=\"text-xs text-muted-foreground leading-none\">{orgsLabel}</p>\n <p className=\"text-sm font-medium leading-none mt-element truncate\">\n {currentOrganization?.name ?? ''}\n </p>\n </div>\n )}\n </>\n );\n };\n\n const renderSettingsSection = () => {\n if (!sections.includes(UserDropdownSection.SETTINGS)) return null;\n\n const settingsLabel = tc('settings');\n const settingsIcon = renderIcon(\n StandardIconReference.SETTINGS,\n { size: IconSize.SM }\n );\n\n // Authored settings entries render inline (icon + label), one per entry,\n // instead of a single \"Settings\" button. The list IS the intent — there is\n // no separate enable flag that could disagree with it.\n if (settingsTargets.length > 0) {\n return (\n <>\n <Separator />\n <div className=\"p-item\">\n <p className=\"text-xs text-muted-foreground mb-item px-card-sm\">{settingsLabel}</p>\n <div className=\"space-y-item-xs\">\n {settingsTargets.map(item => (\n <Button\n key={item.id}\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n className=\"w-full justify-start rounded-sm\"\n onClick={() => handleNavigateToSettingsTarget(item)}\n >\n {item.icon ?? settingsIcon}\n <span className=\"truncate\">{item.label}</span>\n </Button>\n ))}\n </div>\n </div>\n </>\n );\n }\n\n return (\n <>\n <Separator />\n <div className=\"p-item\">\n <Button\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n className=\"w-full justify-start rounded-sm\"\n disabled={!settingsTarget}\n onClick={() => settingsTarget && handleNavigateToSettingsTarget(settingsTarget)}\n >\n {settingsIcon}\n {settingsLabel}\n </Button>\n </div>\n </>\n );\n };\n\n const renderLogoutSection = () => {\n if (!sections.includes(UserDropdownSection.LOGOUT) || !showLogout) return null;\n\n const logoutLabel = tc('logout');\n const logoutIcon = renderIcon(\n StandardIconReference.LOGOUT,\n { size: IconSize.SM }\n );\n\n return (\n <>\n <Separator />\n <div className=\"p-item\">\n <Button\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n onClick={handleLogout}\n className=\"w-full justify-start rounded-sm text-destructive hover:text-destructive\"\n >\n {logoutIcon}\n {logoutLabel}\n </Button>\n </div>\n </>\n );\n };\n\n // ===================================================================\n // Early Return - Not Authenticated\n // ===================================================================\n\n if (!isUserAuthenticated) {\n return null;\n }\n\n if (!isReady) return null;\n\n // ===================================================================\n // Render\n // ===================================================================\n\n const isAvatarOnly = avatarDisplay === UserDropdownAvatarDisplay.AVATAR_ONLY\n || (!avatarDisplay);\n\n return (\n /*\n * `modal={false}` is required, not cosmetic.\n *\n * The trigger below lives INSIDE the menubar (`role=\"banner\"`), while the\n * dropdown content is portaled OUT of it. Radix's default `modal={true}`\n * runs `hideOthers(content)` on open, which sets `aria-hidden=\"true\"` on\n * every subtree outside the portaled content — including the menubar that\n * still hosts the focused trigger (the click that opened the menu focuses\n * the avatar button). The browser then blocks that aria-hidden with\n * \"descendant retained focus\", an accessibility violation.\n *\n * A transient account menu needs none of the modal guarantees (scroll\n * lock, outside-pointer blocking, background AT-hiding), so going\n * non-modal is both the correct UX and removes the invalid\n * aria-hidden-on-a-focused-ancestor by construction. Outside-click and\n * Escape dismissal still work via the DismissableLayer.\n */\n <DropdownMenu open={isOpen} onOpenChange={setIsOpen} modal={false}>\n <DropdownMenuTrigger asChild>\n <Button\n /*\n * The only i18n-INDEPENDENT handle on this menu. Its `aria-label` is a translated string,\n * so a browser scenario keying on it would break in any locale but the default — the same\n * discipline `quick-switcher` follows with `data-component-type`.\n */\n data-component-type=\"user-org-menu\"\n variant={ButtonVariants_Variant.GHOST}\n size={isAvatarOnly ? ButtonSize.ICON : ButtonSize.SM}\n className={isAvatarOnly\n ? 'rounded-full h-9 w-9'\n : 'rounded-full pe-card-sm'\n }\n aria-label={tc('userMenuLabel')}\n >\n {renderTriggerContent()}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n align={popupAlignment.align}\n side={popupAlignment.side}\n className=\"w-72 max-w-[calc(100vw-2rem)] p-0\"\n >\n {renderUserInfoSection()}\n {renderOrgSection()}\n {renderSettingsSection()}\n {renderLogoutSection()}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"menu-user-org.js","sourceRoot":"","sources":["../../../../../../src/components/navigation/app-level/menu-user-org.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EACL,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAExF,OAAO,EACL,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EACtD,MAAM,EAAE,cAAc,EAAE,WAAW,EACnC,MAAM,EAAE,sBAAsB,EAC9B,SAAS,EACT,OAAO,EACP,eAAe,EACf,sBAAsB,EACtB,QAAQ,EAAE,qBAAqB,EAC/B,EAAE,GACH,MAAM,6BAA6B,CAAC;AAIrC,MAAM,CAAC,MAAM,0CAA0C,GAAgD,CAAC,EACtG,aAAa,EACb,kBAAkB,GACnB,EAAE,EAAE;IACH,MAAM,QAAQ,GAAG,sBAAsB,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;IAC3E,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,EAAE,SAAS,EAAE,qBAAqB,CAAC,+BAA+B,EAAE,CAAC,CAAC;IAC9G,MAAM,EAAE,UAAU,EAAE,GAAG,eAAe,EAAE,CAAC;IAEzC,MAAM,EACJ,MAAM,EACN,SAAS,EACT,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,KAAK,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,QAAQ,EACR,aAAa,EACb,eAAe,EACf,UAAU,EACV,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,EACZ,eAAe,EACf,8BAA8B,GAC/B,GAAG,QAAQ,CAAC;IAEb,MAAM,EAAE,GAAG,WAAW,CACpB,CAAC,GAAW,EAAE,EAAE,CAAC,UAAU,CAAC,qBAAqB,CAAC,+BAA+B,EAAE,GAAG,CAAC,EACvF,CAAC,UAAU,CAAC,CACb,CAAC;IAEF,sEAAsE;IACtE,iBAAiB;IACjB,sEAAsE;IAEtE,MAAM,oBAAoB,GAAG,GAAG,EAAE;QAEhC,QAAQ,aAAa,EAAE,CAAC;YACtB,KAAK,yBAAyB,CAAC,WAAW;gBACxC,OAAO,CACL,eAAK,SAAS,EAAC,+BAA+B,aAC5C,MAAC,MAAM,IAAC,SAAS,EAAC,SAAS,aACzB,KAAC,WAAW,IAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAI,EACjD,KAAC,cAAc,IAAC,SAAS,EAAC,SAAS,YAAE,YAAY,GAAkB,IAC5D,EACT,eAAM,SAAS,EAAC,4CAA4C,YAAE,WAAW,GAAQ,IAC7E,CACP,CAAC;YACJ,KAAK,yBAAyB,CAAC,UAAU;gBACvC,OAAO,CACL,eAAK,SAAS,EAAC,+BAA+B,aAC5C,MAAC,MAAM,IAAC,SAAS,EAAC,SAAS,aACzB,KAAC,WAAW,IAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAI,EACjD,KAAC,cAAc,IAAC,SAAS,EAAC,SAAS,YAAE,YAAY,GAAkB,IAC5D,EACT,eAAM,SAAS,EAAC,4CAA4C,YACzD,mBAAmB,EAAE,IAAI,IAAI,WAAW,GACpC,IACH,CACP,CAAC;YACJ,KAAK,yBAAyB,CAAC,IAAI;gBACjC,OAAO,CACL,eAAK,SAAS,EAAC,+BAA+B,aAC5C,MAAC,MAAM,IAAC,SAAS,EAAC,SAAS,aACzB,KAAC,WAAW,IAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAI,EACjD,KAAC,cAAc,IAAC,SAAS,EAAC,SAAS,YAAE,YAAY,GAAkB,IAC5D,EACT,eAAK,SAAS,EAAC,2BAA2B,aACxC,eAAM,SAAS,EAAC,4CAA4C,YAAE,WAAW,GAAQ,EACjF,eAAM,SAAS,EAAC,sDAAsD,YACnE,mBAAmB,EAAE,IAAI,GACrB,IACH,IACF,CACP,CAAC;YACJ,KAAK,yBAAyB,CAAC,WAAW,CAAC;YAC3C;gBACE,OAAO,CACL,MAAC,MAAM,IAAC,SAAS,EAAC,SAAS,aACzB,KAAC,WAAW,IAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAI,EACjD,KAAC,cAAc,IAAC,SAAS,EAAC,SAAS,YAAE,YAAY,GAAkB,IAC5D,CACV,CAAC;QACN,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,qBAAqB,GAAG,GAAG,EAAE;QACjC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC,SAAS,CAAC;YAAE,OAAO,IAAI,CAAC;QAEnE,OAAO,CACL,eAAK,SAAS,EAAC,oBAAoB,aACjC,YAAG,SAAS,EAAC,2CAA2C,YAAE,WAAW,GAAK,EAC1E,YAAG,SAAS,EAAC,6DAA6D,YAAE,KAAK,GAAK,IAClF,CACP,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC5B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC,YAAY,CAAC;YAAE,OAAO,IAAI,CAAC;QAEtE,MAAM,eAAe,GAAG,aAAa,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;QAClE,MAAM,SAAS,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC;QACtC,MAAM,gBAAgB,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QAC/F,MAAM,mBAAmB,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC,CAAC;QAC1G,MAAM,SAAS,GAAG;YAChB,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE;YACjE,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,CAAC,qBAAqB,CAAC,EAAE,aAAa,EAAE,mBAAmB,EAAE;SACzF,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAElD,MAAM,SAAS,GAAG,UAAU,CAC1B,qBAAqB,CAAC,KAAK,EAC3B,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CACtB,CAAC;QAEF,OAAO,CACL,8BACE,KAAC,SAAS,KAAG,EAEZ,eAAe,IAAI,eAAe,IAAI,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;gBAC3F,0CAA0C;gBAC1C,cAAK,SAAS,EAAC,QAAQ,YAGpB,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CACtB,eAAqB,SAAS,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,SAAS,CAAC,aACtE,YAAG,SAAS,EAAC,kDAAkD,YAAE,KAAK,CAAC,KAAK,GAAK,EACjF,cAAK,SAAS,EAAC,iBAAiB,YAC7B,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;oCAC7B,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,KAAK,mBAAmB,EAAE,GAAG,CAAC;oCACxD,OAAO,CACL,MAAC,MAAM,2BAQe,sBAAsB,0BACpB,GAAG,CAAC,GAAG,mBACd,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAC5C,OAAO,EAAE,sBAAsB,CAAC,KAAK,EACrC,IAAI,EAAE,UAAU,CAAC,EAAE,EACnB,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EACvC,SAAS,EAAE,EAAE,CAAC,yCAAyC,EAAE,UAAU,IAAI,gDAAgD,CAAC,aAExH,eAAM,SAAS,EAAE,EAAE,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC,YAC5E,SAAS,GACL,EACP,gBAAM,SAAS,EAAC,mCAAmC,aACjD,eAAM,SAAS,EAAC,UAAU,YAAE,GAAG,CAAC,IAAI,GAAQ,EAC3C,GAAG,CAAC,2BAA2B,CAAC,CAAC,CAAC,CACjC,eAAM,SAAS,EAAC,wCAAwC,YACrD,UAAU,CAAC,qBAAqB,CAAC,+BAA+B,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,2BAA2B,EAAE,CAAC,GACzH,CACR,CAAC,CAAC,CAAC,IAAI,IACH,KAzBF,GAAG,CAAC,GAAG,CA0BL,CACV,CAAC;gCACJ,CAAC,CAAC,GACE,KApCE,KAAK,CAAC,GAAG,CAqCb,CACP,CAAC,GACE,CACP,CAAC,CAAC,CAAC;gBACF,0CAA0C;gBAC1C,eAAK,SAAS,EAAC,oBAAoB,aACjC,YAAG,SAAS,EAAC,4CAA4C,YAAE,SAAS,GAAK,EACzE,YAAG,SAAS,EAAC,sDAAsD,YAChE,mBAAmB,EAAE,IAAI,IAAI,EAAE,GAC9B,IACA,CACP,IACA,CACJ,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,qBAAqB,GAAG,GAAG,EAAE;QACjC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QAElE,MAAM,aAAa,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,YAAY,GAAG,UAAU,CAC7B,qBAAqB,CAAC,QAAQ,EAC9B,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CACtB,CAAC;QAEF,yEAAyE;QACzE,2EAA2E;QAC3E,uDAAuD;QACvD,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,OAAO,CACL,8BACE,KAAC,SAAS,KAAG,EACb,eAAK,SAAS,EAAC,QAAQ,aACrB,YAAG,SAAS,EAAC,kDAAkD,YAAE,aAAa,GAAK,EACnF,cAAK,SAAS,EAAC,iBAAiB,YAC7B,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAC3B,MAAC,MAAM,IAEL,OAAO,EAAE,sBAAsB,CAAC,KAAK,EACrC,IAAI,EAAE,UAAU,CAAC,EAAE,EACnB,SAAS,EAAC,iCAAiC,EAC3C,OAAO,EAAE,GAAG,EAAE,CAAC,8BAA8B,CAAC,IAAI,CAAC,aAElD,IAAI,CAAC,IAAI,IAAI,YAAY,EAC1B,eAAM,SAAS,EAAC,UAAU,YAAE,IAAI,CAAC,KAAK,GAAQ,KAPzC,IAAI,CAAC,EAAE,CAQL,CACV,CAAC,GACE,IACF,IACL,CACJ,CAAC;QACJ,CAAC;QAED,OAAO,CACL,8BACE,KAAC,SAAS,KAAG,EACb,cAAK,SAAS,EAAC,QAAQ,YACrB,MAAC,MAAM,IACL,OAAO,EAAE,sBAAsB,CAAC,KAAK,EACrC,IAAI,EAAE,UAAU,CAAC,EAAE,EACnB,SAAS,EAAC,iCAAiC,EAC3C,QAAQ,EAAE,CAAC,cAAc,EACzB,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,IAAI,8BAA8B,CAAC,cAAc,CAAC,aAE9E,YAAY,EACZ,aAAa,IACP,GACL,IACL,CACJ,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,mBAAmB,GAAG,GAAG,EAAE;QAC/B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAE/E,MAAM,WAAW,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,UAAU,GAAG,UAAU,CAC3B,qBAAqB,CAAC,MAAM,EAC5B,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CACtB,CAAC;QAEF,OAAO,CACL,8BACE,KAAC,SAAS,KAAG,EACb,cAAK,SAAS,EAAC,QAAQ,YACrB,MAAC,MAAM,IACL,OAAO,EAAE,sBAAsB,CAAC,KAAK,EACrC,IAAI,EAAE,UAAU,CAAC,EAAE,EACnB,OAAO,EAAE,YAAY,EACrB,SAAS,EAAC,yEAAyE,aAElF,UAAU,EACV,WAAW,IACL,GACL,IACL,CACJ,CAAC;IACJ,CAAC,CAAC;IAEF,sEAAsE;IACtE,mCAAmC;IACnC,sEAAsE;IAEtE,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,sEAAsE;IACtE,SAAS;IACT,sEAAsE;IAEtE,MAAM,YAAY,GAAG,aAAa,KAAK,yBAAyB,CAAC,WAAW;WACvE,CAAC,CAAC,aAAa,CAAC,CAAC;IAEtB,OAAO;IACL;;;;;;;;;;;;;;;;OAgBG;IACH,MAAC,YAAY,IAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,aAC/D,KAAC,mBAAmB,IAAC,OAAO,kBAC1B,KAAC,MAAM;gBACL;;;;mBAIG;2CACiB,eAAe,EACnC,OAAO,EAAE,sBAAsB,CAAC,KAAK,EACrC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,EACpD,SAAS,EAAE,YAAY;wBACrB,CAAC,CAAC,sBAAsB;wBACxB,CAAC,CAAC,yBAAyB,gBAEjB,EAAE,CAAC,eAAe,CAAC,YAE9B,oBAAoB,EAAE,GAChB,GACW,EACtB,MAAC,mBAAmB,IAClB,KAAK,EAAE,cAAc,CAAC,KAAK,EAC3B,IAAI,EAAE,cAAc,CAAC,IAAI,EACzB,SAAS,EAAC,mCAAmC,aAE5C,qBAAqB,EAAE,EACvB,gBAAgB,EAAE,EAClB,qBAAqB,EAAE,EACvB,mBAAmB,EAAE,IACF,IACT,CAChB,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import React, { useCallback } from 'react';\nimport {\n UserDropdownSection,\n UserDropdownAvatarDisplay,\n} from '@wildo-ai/saas-frontend-lib';\n\nimport { ButtonSize, FrontendComponentType } from '@wildo-ai/presets-components-models';\n\nimport {\n DropdownMenu, DropdownMenuContent, DropdownMenuTrigger,\n Avatar, AvatarFallback, AvatarImage,\n Button, ButtonVariants_Variant,\n Separator,\n useI18n,\n useIconRegistry,\n useMenuUserOrgBehavior,\n IconSize, StandardIconReference,\n cn,\n} from '@wildo-ai/saas-frontend-lib';\n\nimport type { ApplicationLevelProps_MenuUserOrg } from '@wildo-ai/saas-frontend-lib';\n\nexport const ApplicationLevelPreset_MenuUserOrg_Default: React.FC<ApplicationLevelProps_MenuUserOrg> = ({\n containerType,\n containerPlacement,\n}) => {\n const behavior = useMenuUserOrgBehavior(containerType, containerPlacement);\n const { tComponent, isReady } = useI18n({ component: FrontendComponentType.APPLICATION_LEVEL_USER_DROPDOWN });\n const { renderIcon } = useIconRegistry();\n\n const {\n isOpen,\n setIsOpen,\n isUserAuthenticated,\n userInitials,\n displayName,\n email,\n avatarUrl,\n currentOrganization,\n organizations,\n sections,\n avatarDisplay,\n showOrgSwitcher,\n showLogout,\n settingsTarget,\n settingsTargets,\n popupAlignment,\n handleLogout,\n handleSwitchOrg,\n handleNavigateToSettingsTarget,\n } = behavior;\n\n const tc = useCallback(\n (key: string) => tComponent(FrontendComponentType.APPLICATION_LEVEL_USER_DROPDOWN, key),\n [tComponent],\n );\n\n // ===================================================================\n // Render Helpers\n // ===================================================================\n\n const renderTriggerContent = () => {\n\n switch (avatarDisplay) {\n case UserDropdownAvatarDisplay.AVATAR_NAME:\n return (\n <div className=\"flex items-center gap-element\">\n <Avatar className=\"h-8 w-8\">\n <AvatarImage src={avatarUrl} alt={displayName} />\n <AvatarFallback className=\"text-xs\">{userInitials}</AvatarFallback>\n </Avatar>\n <span className=\"text-sm font-medium max-w-[120px] truncate\">{displayName}</span>\n </div>\n );\n case UserDropdownAvatarDisplay.AVATAR_ORG:\n return (\n <div className=\"flex items-center gap-element\">\n <Avatar className=\"h-8 w-8\">\n <AvatarImage src={avatarUrl} alt={displayName} />\n <AvatarFallback className=\"text-xs\">{userInitials}</AvatarFallback>\n </Avatar>\n <span className=\"text-sm font-medium max-w-[120px] truncate\">\n {currentOrganization?.name ?? displayName}\n </span>\n </div>\n );\n case UserDropdownAvatarDisplay.FULL:\n return (\n <div className=\"flex items-center gap-element\">\n <Avatar className=\"h-8 w-8\">\n <AvatarImage src={avatarUrl} alt={displayName} />\n <AvatarFallback className=\"text-xs\">{userInitials}</AvatarFallback>\n </Avatar>\n <div className=\"flex flex-col items-start\">\n <span className=\"text-sm font-medium max-w-[120px] truncate\">{displayName}</span>\n <span className=\"text-xs text-muted-foreground max-w-[120px] truncate\">\n {currentOrganization?.name}\n </span>\n </div>\n </div>\n );\n case UserDropdownAvatarDisplay.AVATAR_ONLY:\n default:\n return (\n <Avatar className=\"h-8 w-8\">\n <AvatarImage src={avatarUrl} alt={displayName} />\n <AvatarFallback className=\"text-xs\">{userInitials}</AvatarFallback>\n </Avatar>\n );\n }\n };\n\n const renderUserInfoSection = () => {\n if (!sections.includes(UserDropdownSection.USER_INFO)) return null;\n\n return (\n <div className=\"px-card py-card-sm\">\n <p className=\"text-sm font-medium leading-none truncate\">{displayName}</p>\n <p className=\"text-xs leading-none text-muted-foreground mt-item truncate\">{email}</p>\n </div>\n );\n };\n\n const renderOrgSection = () => {\n if (!sections.includes(UserDropdownSection.ORG_SWITCHER)) return null;\n\n const hasMultipleOrgs = organizations && organizations.length > 1;\n const orgsLabel = tc('organizations');\n const ownOrganizations = (organizations ?? []).filter(org => !org.viaProviderOrganizationName);\n const clientOrganizations = (organizations ?? []).filter(org => Boolean(org.viaProviderOrganizationName));\n const orgGroups = [\n { key: 'own', label: orgsLabel, organizations: ownOrganizations },\n { key: 'clients', label: tc('clientOrganizations'), organizations: clientOrganizations },\n ].filter(group => group.organizations.length > 0);\n\n const checkIcon = renderIcon(\n StandardIconReference.CHECK,\n { size: IconSize.SM }\n );\n\n return (\n <>\n <Separator />\n\n {hasMultipleOrgs && showOrgSwitcher && sections.includes(UserDropdownSection.ORG_SWITCHER) ? (\n /* Multiple orgs — full selectable list */\n <div className=\"p-item\">\n {/* Own organizations first; the clients a service firm's expert works in follow under their\n own heading (#1597), each naming the firm through which it is reached. */}\n {orgGroups.map(group => (\n <div key={group.key} className={cn(group.key === 'clients' && 'mt-item')}>\n <p className=\"text-xs text-muted-foreground mb-item px-card-sm\">{group.label}</p>\n <div className=\"space-y-item-xs\">\n {group.organizations.map(org => {\n const isSelected = org._id === currentOrganization?._id;\n return (\n <Button\n key={org._id}\n /*\n * The org's IDENTITY on the element, not its name: a scenario asserting which\n * organization is active must not have to match a display name it did not choose,\n * and `data-selected` states the current one without reading the check icon —\n * which is an icon, and therefore not assertable text at all.\n */\n data-component-type=\"user-org-menu-option\"\n data-organization-id={org._id}\n data-selected={isSelected ? 'true' : 'false'}\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n onClick={() => handleSwitchOrg(org._id)}\n className={cn('w-full justify-start text-sm rounded-sm', isSelected && 'bg-primary/10 text-primary hover:bg-primary/15')}\n >\n <span className={cn('flex-shrink-0', isSelected ? 'text-primary' : 'invisible')}>\n {checkIcon}\n </span>\n <span className=\"flex min-w-0 flex-col items-start\">\n <span className=\"truncate\">{org.name}</span>\n {org.viaProviderOrganizationName ? (\n <span className=\"truncate text-xs text-muted-foreground\">\n {tComponent(FrontendComponentType.APPLICATION_LEVEL_USER_DROPDOWN, 'servedViaFirm', { firm: org.viaProviderOrganizationName })}\n </span>\n ) : null}\n </span>\n </Button>\n );\n })}\n </div>\n </div>\n ))}\n </div>\n ) : (\n /* Single org — non-interactive display */\n <div className=\"px-card py-card-sm\">\n <p className=\"text-xs text-muted-foreground leading-none\">{orgsLabel}</p>\n <p className=\"text-sm font-medium leading-none mt-element truncate\">\n {currentOrganization?.name ?? ''}\n </p>\n </div>\n )}\n </>\n );\n };\n\n const renderSettingsSection = () => {\n if (!sections.includes(UserDropdownSection.SETTINGS)) return null;\n\n const settingsLabel = tc('settings');\n const settingsIcon = renderIcon(\n StandardIconReference.SETTINGS,\n { size: IconSize.SM }\n );\n\n // Authored settings entries render inline (icon + label), one per entry,\n // instead of a single \"Settings\" button. The list IS the intent — there is\n // no separate enable flag that could disagree with it.\n if (settingsTargets.length > 0) {\n return (\n <>\n <Separator />\n <div className=\"p-item\">\n <p className=\"text-xs text-muted-foreground mb-item px-card-sm\">{settingsLabel}</p>\n <div className=\"space-y-item-xs\">\n {settingsTargets.map(item => (\n <Button\n key={item.id}\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n className=\"w-full justify-start rounded-sm\"\n onClick={() => handleNavigateToSettingsTarget(item)}\n >\n {item.icon ?? settingsIcon}\n <span className=\"truncate\">{item.label}</span>\n </Button>\n ))}\n </div>\n </div>\n </>\n );\n }\n\n return (\n <>\n <Separator />\n <div className=\"p-item\">\n <Button\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n className=\"w-full justify-start rounded-sm\"\n disabled={!settingsTarget}\n onClick={() => settingsTarget && handleNavigateToSettingsTarget(settingsTarget)}\n >\n {settingsIcon}\n {settingsLabel}\n </Button>\n </div>\n </>\n );\n };\n\n const renderLogoutSection = () => {\n if (!sections.includes(UserDropdownSection.LOGOUT) || !showLogout) return null;\n\n const logoutLabel = tc('logout');\n const logoutIcon = renderIcon(\n StandardIconReference.LOGOUT,\n { size: IconSize.SM }\n );\n\n return (\n <>\n <Separator />\n <div className=\"p-item\">\n <Button\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n onClick={handleLogout}\n className=\"w-full justify-start rounded-sm text-destructive hover:text-destructive\"\n >\n {logoutIcon}\n {logoutLabel}\n </Button>\n </div>\n </>\n );\n };\n\n // ===================================================================\n // Early Return - Not Authenticated\n // ===================================================================\n\n if (!isUserAuthenticated) {\n return null;\n }\n\n if (!isReady) return null;\n\n // ===================================================================\n // Render\n // ===================================================================\n\n const isAvatarOnly = avatarDisplay === UserDropdownAvatarDisplay.AVATAR_ONLY\n || (!avatarDisplay);\n\n return (\n /*\n * `modal={false}` is required, not cosmetic.\n *\n * The trigger below lives INSIDE the menubar (`role=\"banner\"`), while the\n * dropdown content is portaled OUT of it. Radix's default `modal={true}`\n * runs `hideOthers(content)` on open, which sets `aria-hidden=\"true\"` on\n * every subtree outside the portaled content — including the menubar that\n * still hosts the focused trigger (the click that opened the menu focuses\n * the avatar button). The browser then blocks that aria-hidden with\n * \"descendant retained focus\", an accessibility violation.\n *\n * A transient account menu needs none of the modal guarantees (scroll\n * lock, outside-pointer blocking, background AT-hiding), so going\n * non-modal is both the correct UX and removes the invalid\n * aria-hidden-on-a-focused-ancestor by construction. Outside-click and\n * Escape dismissal still work via the DismissableLayer.\n */\n <DropdownMenu open={isOpen} onOpenChange={setIsOpen} modal={false}>\n <DropdownMenuTrigger asChild>\n <Button\n /*\n * The only i18n-INDEPENDENT handle on this menu. Its `aria-label` is a translated string,\n * so a browser scenario keying on it would break in any locale but the default — the same\n * discipline `quick-switcher` follows with `data-component-type`.\n */\n data-component-type=\"user-org-menu\"\n variant={ButtonVariants_Variant.GHOST}\n size={isAvatarOnly ? ButtonSize.ICON : ButtonSize.SM}\n className={isAvatarOnly\n ? 'rounded-full h-9 w-9'\n : 'rounded-full pe-card-sm'\n }\n aria-label={tc('userMenuLabel')}\n >\n {renderTriggerContent()}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n align={popupAlignment.align}\n side={popupAlignment.side}\n className=\"w-72 max-w-[calc(100vw-2rem)] p-0\"\n >\n {renderUserInfoSection()}\n {renderOrgSection()}\n {renderSettingsSection()}\n {renderLogoutSection()}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"menu-user-org.labels.d.ts","sourceRoot":"","sources":["../../../../../../src/components/navigation/app-level/menu-user-org.labels.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EAEzB,MAAM,qCAAqC,CAAC;AAM7C,eAAO,MAAM,kCAAkC,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"menu-user-org.labels.d.ts","sourceRoot":"","sources":["../../../../../../src/components/navigation/app-level/menu-user-org.labels.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EAEzB,MAAM,qCAAqC,CAAC;AAM7C,eAAO,MAAM,kCAAkC,EAAE,mBAAmB,EAmBnE,CAAC"}
|