@lattice-php/lattice 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +10 -0
  2. package/dist/action/components/action-form.js +14 -9
  3. package/dist/action/components/action-form.js.map +1 -1
  4. package/dist/action/components/action.js +2 -1
  5. package/dist/action/components/action.js.map +1 -1
  6. package/dist/action/hooks/use-action.js +42 -35
  7. package/dist/action/hooks/use-action.js.map +1 -1
  8. package/dist/action/lib/action-label.d.ts +2 -0
  9. package/dist/action/lib/action-label.js +9 -0
  10. package/dist/action/lib/action-label.js.map +1 -0
  11. package/dist/action/lib/run-action.d.ts +7 -7
  12. package/dist/action/lib/run-action.js +8 -7
  13. package/dist/action/lib/run-action.js.map +1 -1
  14. package/dist/form/components/form.js +3 -1
  15. package/dist/form/components/form.js.map +1 -1
  16. package/dist/format/number.d.ts +1 -1
  17. package/dist/format/number.js.map +1 -1
  18. package/dist/format/value.d.ts +1 -1
  19. package/dist/format/value.js.map +1 -1
  20. package/dist/notifications/components/notifications.js +1 -0
  21. package/dist/notifications/components/notifications.js.map +1 -1
  22. package/dist/table/components/bulk-bar.js +15 -14
  23. package/dist/table/components/bulk-bar.js.map +1 -1
  24. package/dist/table/components/cells/numeric-cell.d.ts +1 -1
  25. package/dist/table/components/cells/numeric-cell.js.map +1 -1
  26. package/dist/table/lib/bulk.js +2 -1
  27. package/dist/table/lib/bulk.js.map +1 -1
  28. package/dist/toast/index.d.ts +1 -1
  29. package/dist/toast/index.js +2 -2
  30. package/dist/types/generated.d.ts +1 -1
  31. package/dist/ui/modal.js +3 -1
  32. package/dist/ui/modal.js.map +1 -1
  33. package/dist-standalone/chunks/{subscriptions-B_ISgA7V.js → subscriptions-DK_s_F2g.js} +1 -1
  34. package/dist-standalone/chunks/use-effect-dispatcher-EVZxmfoo.js +97 -0
  35. package/dist-standalone/lattice.js +15 -15
  36. package/dist-standalone/manifest.json +4 -4
  37. package/package.json +3 -3
  38. package/dist-standalone/chunks/use-effect-dispatcher-D1wPPwHj.js +0 -97
@@ -1 +1 @@
1
- {"version":3,"file":"bulk-bar.js","names":[],"sources":["../../../resources/js/table/components/bulk-bar.tsx"],"sourcesContent":["import { useHttp } from \"@inertiajs/react\";\nimport { useState } from \"react\";\nimport { ActionForm, runAction } from \"@lattice-php/lattice/action\";\nimport { getActionEffects } from \"@lattice-php/lattice/effects/dispatch\";\nimport type { ActionResponse } from \"@lattice-php/lattice/effects/dispatch\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport { withHeaders } from \"@lattice-php/lattice/core/headers\";\nimport { Button } from \"@lattice-php/lattice/ui/button\";\nimport { ConfirmDialog } from \"@lattice-php/lattice/ui/confirm-dialog\";\nimport { Spinner } from \"@lattice-php/lattice/ui/spinner\";\nimport { prefixedTestId } from \"@lattice-php/lattice/core/test-id\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { BulkAction } from \"@lattice-php/lattice/table/lib/bulk\";\n\ntype BulkData = {\n allMatching?: boolean;\n selected?: string[];\n};\n\nexport function BulkBar({\n actions,\n selectedKeys,\n allMatching,\n total,\n query,\n canSelectAllMatching,\n onSelectAllMatching,\n onCompleted,\n}: {\n actions: BulkAction[];\n selectedKeys: string[];\n allMatching: boolean;\n total?: number;\n query: Record<string, unknown>;\n canSelectAllMatching: boolean;\n onSelectAllMatching: () => void;\n onCompleted: () => void;\n}) {\n const { t } = useT(\"lattice\");\n const http = useHttp<BulkData, ActionResponse>({});\n const dispatch = useEffectDispatcher();\n const [confirming, setConfirming] = useState<BulkAction | null>(null);\n const [filling, setFilling] = useState<BulkAction | null>(null);\n\n const selectionPayload = (): Record<string, unknown> =>\n allMatching ? { allMatching: true, ...query } : { selected: selectedKeys };\n\n async function submit(action: BulkAction): Promise<void> {\n http.transform((data) => ({ ...data, ...selectionPayload() }));\n\n const ok = await runAction(\n () => http[action.method](action.endpoint, { headers: withHeaders(action.ref ?? \"\") }),\n dispatch,\n );\n\n if (ok) {\n setConfirming(null);\n onCompleted();\n }\n }\n\n function run(action: BulkAction): void {\n if (action.form) {\n setFilling(action);\n\n return;\n }\n\n if (action.confirmation) {\n setConfirming(action);\n\n return;\n }\n\n void submit(action);\n }\n\n const count = allMatching ? (total ?? selectedKeys.length) : selectedKeys.length;\n\n return (\n <div className=\"flex flex-wrap items-center gap-3 border-b border-lt-border bg-lt-muted/50 p-4 text-sm\">\n <span className=\"font-medium\">\n {allMatching\n ? t(\"table.bulk.all-selected\", \"All {{count}} selected\", { count })\n : t(\"table.bulk.selected\", \"{{count}} selected\", { count })}\n </span>\n {canSelectAllMatching && (\n <button\n type=\"button\"\n data-test=\"bulk-select-all-matching\"\n className=\"font-medium text-lt-primary underline underline-offset-2\"\n onClick={onSelectAllMatching}\n >\n {t(\"table.bulk.select-all-matching\", \"Select all {{total}} matching\", { total })}\n </button>\n )}\n <div className=\"flex flex-wrap items-center gap-2\">\n {actions.map((action) => (\n <Button\n key={action.id}\n type=\"button\"\n data-test={prefixedTestId(\"bulk-action\", action.id)}\n variant={action.variant}\n disabled={http.processing}\n onClick={() => run(action)}\n >\n {http.processing && <Spinner />}\n {action.label}\n </Button>\n ))}\n </div>\n\n {confirming?.confirmation && (\n <ConfirmDialog\n title={confirming.confirmation.title ?? confirming.label}\n description={confirming.confirmation.description ?? undefined}\n confirmLabel={confirming.confirmation.confirmLabel ?? confirming.label}\n cancelLabel={confirming.confirmation.cancelLabel ?? t(\"common.cancel\", \"Cancel\")}\n confirmVariant={confirming.variant}\n processing={http.processing}\n onConfirm={() => void submit(confirming)}\n onCancel={() => setConfirming(null)}\n />\n )}\n\n {filling?.form && (\n <ActionForm\n cancelLabel={filling.confirmation?.cancelLabel ?? t(\"common.cancel\", \"Cancel\")}\n componentRef={filling.ref}\n description={filling.confirmation?.description ?? undefined}\n endpoint={filling.endpoint}\n extraData={selectionPayload()}\n formNode={filling.form}\n method={filling.method}\n onClose={() => setFilling(null)}\n onSuccess={(response) => {\n dispatch(getActionEffects(response.effects));\n setFilling(null);\n onCompleted();\n }}\n placement={filling.modalSide ?? \"center\"}\n submitLabel={filling.confirmation?.confirmLabel ?? filling.label}\n title={filling.confirmation?.title ?? filling.label}\n width={filling.modalWidth ?? undefined}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAmBA,SAAgB,QAAQ,EACtB,SACA,cACA,aACA,OACA,OACA,sBACA,qBACA,eAUC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,OAAO,QAAkC,CAAC,CAAC;CACjD,MAAM,WAAW,oBAAoB;CACrC,MAAM,CAAC,YAAY,iBAAiB,SAA4B,IAAI;CACpE,MAAM,CAAC,SAAS,cAAc,SAA4B,IAAI;CAE9D,MAAM,yBACJ,cAAc;EAAE,aAAa;EAAM,GAAG;CAAM,IAAI,EAAE,UAAU,aAAa;CAE3E,eAAe,OAAO,QAAmC;EACvD,KAAK,WAAW,UAAU;GAAE,GAAG;GAAM,GAAG,iBAAiB;EAAE,EAAE;EAO7D,IAAI,MALa,gBACT,KAAK,OAAO,QAAQ,OAAO,UAAU,EAAE,SAAS,YAAY,OAAO,OAAO,EAAE,EAAE,CAAC,GACrF,QACF,GAEQ;GACN,cAAc,IAAI;GAClB,YAAY;EACd;CACF;CAEA,SAAS,IAAI,QAA0B;EACrC,IAAI,OAAO,MAAM;GACf,WAAW,MAAM;GAEjB;EACF;EAEA,IAAI,OAAO,cAAc;GACvB,cAAc,MAAM;GAEpB;EACF;EAEA,OAAY,MAAM;CACpB;CAEA,MAAM,QAAQ,cAAe,SAAS,aAAa,SAAU,aAAa;CAE1E,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,QAAD;IAAM,WAAU;cACb,cACG,EAAE,2BAA2B,0BAA0B,EAAE,MAAM,CAAC,IAChE,EAAE,uBAAuB,sBAAsB,EAAE,MAAM,CAAC;GACxD,CAAA;GACL,wBACC,oBAAC,UAAD;IACE,MAAK;IACL,aAAU;IACV,WAAU;IACV,SAAS;cAER,EAAE,kCAAkC,iCAAiC,EAAE,MAAM,CAAC;GACzE,CAAA;GAEV,oBAAC,OAAD;IAAK,WAAU;cACZ,QAAQ,KAAK,WACZ,qBAAC,QAAD;KAEE,MAAK;KACL,aAAW,eAAe,eAAe,OAAO,EAAE;KAClD,SAAS,OAAO;KAChB,UAAU,KAAK;KACf,eAAe,IAAI,MAAM;eAN3B,CAQG,KAAK,cAAc,oBAAC,SAAD,CAAU,CAAA,GAC7B,OAAO,KACF;OATD,OAAO,EASN,CACT;GACE,CAAA;GAEJ,YAAY,gBACX,oBAAC,eAAD;IACE,OAAO,WAAW,aAAa,SAAS,WAAW;IACnD,aAAa,WAAW,aAAa,eAAe,KAAA;IACpD,cAAc,WAAW,aAAa,gBAAgB,WAAW;IACjE,aAAa,WAAW,aAAa,eAAe,EAAE,iBAAiB,QAAQ;IAC/E,gBAAgB,WAAW;IAC3B,YAAY,KAAK;IACjB,iBAAiB,KAAK,OAAO,UAAU;IACvC,gBAAgB,cAAc,IAAI;GACnC,CAAA;GAGF,SAAS,QACR,oBAAC,YAAD;IACE,aAAa,QAAQ,cAAc,eAAe,EAAE,iBAAiB,QAAQ;IAC7E,cAAc,QAAQ;IACtB,aAAa,QAAQ,cAAc,eAAe,KAAA;IAClD,UAAU,QAAQ;IAClB,WAAW,iBAAiB;IAC5B,UAAU,QAAQ;IAClB,QAAQ,QAAQ;IAChB,eAAe,WAAW,IAAI;IAC9B,YAAY,aAAa;KACvB,SAAS,iBAAiB,SAAS,OAAO,CAAC;KAC3C,WAAW,IAAI;KACf,YAAY;IACd;IACA,WAAW,QAAQ,aAAa;IAChC,aAAa,QAAQ,cAAc,gBAAgB,QAAQ;IAC3D,OAAO,QAAQ,cAAc,SAAS,QAAQ;IAC9C,OAAO,QAAQ,cAAc,KAAA;GAC9B,CAAA;EAEA;;AAET"}
1
+ {"version":3,"file":"bulk-bar.js","names":[],"sources":["../../../resources/js/table/components/bulk-bar.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { ActionForm, runAction } from \"@lattice-php/lattice/action\";\nimport { apiFetch } from \"@lattice-php/lattice/core/api\";\nimport { useEffectDispatcher } from \"@lattice-php/lattice/effects/use-effect-dispatcher\";\nimport { Button } from \"@lattice-php/lattice/ui/button\";\nimport { ConfirmDialog } from \"@lattice-php/lattice/ui/confirm-dialog\";\nimport { Spinner } from \"@lattice-php/lattice/ui/spinner\";\nimport { prefixedTestId } from \"@lattice-php/lattice/core/test-id\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\nimport type { BulkAction } from \"@lattice-php/lattice/table/lib/bulk\";\n\nexport function BulkBar({\n actions,\n selectedKeys,\n allMatching,\n total,\n query,\n canSelectAllMatching,\n onSelectAllMatching,\n onCompleted,\n}: {\n actions: BulkAction[];\n selectedKeys: string[];\n allMatching: boolean;\n total?: number;\n query: Record<string, unknown>;\n canSelectAllMatching: boolean;\n onSelectAllMatching: () => void;\n onCompleted: () => void;\n}) {\n const { t } = useT(\"lattice\");\n const [processing, setProcessing] = useState(false);\n const dispatch = useEffectDispatcher();\n const [confirming, setConfirming] = useState<BulkAction | null>(null);\n const [filling, setFilling] = useState<BulkAction | null>(null);\n\n const selectionPayload = (): Record<string, unknown> =>\n allMatching ? { allMatching: true, ...query } : { selected: selectedKeys };\n\n async function submit(action: BulkAction): Promise<void> {\n setProcessing(true);\n\n const ok = await runAction(\n () =>\n apiFetch(action.endpoint, {\n method: action.method,\n ref: action.ref,\n body: JSON.stringify(selectionPayload()),\n throwOnError: false,\n }),\n dispatch,\n );\n\n setProcessing(false);\n\n if (ok) {\n setConfirming(null);\n onCompleted();\n }\n }\n\n function run(action: BulkAction): void {\n if (action.form) {\n setFilling(action);\n\n return;\n }\n\n if (action.confirmation) {\n setConfirming(action);\n\n return;\n }\n\n void submit(action);\n }\n\n const count = allMatching ? (total ?? selectedKeys.length) : selectedKeys.length;\n\n return (\n <div className=\"flex flex-wrap items-center gap-3 border-b border-lt-border bg-lt-muted/50 p-4 text-sm\">\n <span className=\"font-medium\">\n {allMatching\n ? t(\"table.bulk.all-selected\", \"All {{count}} selected\", { count })\n : t(\"table.bulk.selected\", \"{{count}} selected\", { count })}\n </span>\n {canSelectAllMatching && (\n <button\n type=\"button\"\n data-test=\"bulk-select-all-matching\"\n className=\"font-medium text-lt-primary underline underline-offset-2\"\n onClick={onSelectAllMatching}\n >\n {t(\"table.bulk.select-all-matching\", \"Select all {{total}} matching\", { total })}\n </button>\n )}\n <div className=\"flex flex-wrap items-center gap-2\">\n {actions.map((action) => (\n <Button\n key={action.id}\n type=\"button\"\n data-test={prefixedTestId(\"bulk-action\", action.id)}\n variant={action.variant}\n disabled={processing}\n onClick={() => run(action)}\n >\n {processing && <Spinner />}\n {action.label}\n </Button>\n ))}\n </div>\n\n {confirming?.confirmation && (\n <ConfirmDialog\n title={confirming.confirmation.title ?? confirming.label}\n description={confirming.confirmation.description ?? undefined}\n confirmLabel={confirming.confirmation.confirmLabel ?? confirming.label}\n cancelLabel={confirming.confirmation.cancelLabel ?? t(\"common.cancel\", \"Cancel\")}\n confirmVariant={confirming.variant}\n processing={processing}\n onConfirm={() => void submit(confirming)}\n onCancel={() => setConfirming(null)}\n />\n )}\n\n {filling?.form && (\n <ActionForm\n cancelLabel={filling.confirmation?.cancelLabel ?? t(\"common.cancel\", \"Cancel\")}\n componentRef={filling.ref}\n description={filling.confirmation?.description ?? undefined}\n endpoint={filling.endpoint}\n extraData={selectionPayload()}\n formNode={filling.form}\n method={filling.method}\n onClose={() => setFilling(null)}\n onSuccess={() => {\n setFilling(null);\n onCompleted();\n }}\n placement={filling.modalSide ?? \"center\"}\n submitLabel={filling.confirmation?.confirmLabel ?? filling.label}\n title={filling.confirmation?.title ?? filling.label}\n width={filling.modalWidth ?? undefined}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAWA,SAAgB,QAAQ,EACtB,SACA,cACA,aACA,OACA,OACA,sBACA,qBACA,eAUC;CACD,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,MAAM,WAAW,oBAAoB;CACrC,MAAM,CAAC,YAAY,iBAAiB,SAA4B,IAAI;CACpE,MAAM,CAAC,SAAS,cAAc,SAA4B,IAAI;CAE9D,MAAM,yBACJ,cAAc;EAAE,aAAa;EAAM,GAAG;CAAM,IAAI,EAAE,UAAU,aAAa;CAE3E,eAAe,OAAO,QAAmC;EACvD,cAAc,IAAI;EAElB,MAAM,KAAK,MAAM,gBAEb,SAAS,OAAO,UAAU;GACxB,QAAQ,OAAO;GACf,KAAK,OAAO;GACZ,MAAM,KAAK,UAAU,iBAAiB,CAAC;GACvC,cAAc;EAChB,CAAC,GACH,QACF;EAEA,cAAc,KAAK;EAEnB,IAAI,IAAI;GACN,cAAc,IAAI;GAClB,YAAY;EACd;CACF;CAEA,SAAS,IAAI,QAA0B;EACrC,IAAI,OAAO,MAAM;GACf,WAAW,MAAM;GAEjB;EACF;EAEA,IAAI,OAAO,cAAc;GACvB,cAAc,MAAM;GAEpB;EACF;EAEA,OAAY,MAAM;CACpB;CAEA,MAAM,QAAQ,cAAe,SAAS,aAAa,SAAU,aAAa;CAE1E,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,QAAD;IAAM,WAAU;cACb,cACG,EAAE,2BAA2B,0BAA0B,EAAE,MAAM,CAAC,IAChE,EAAE,uBAAuB,sBAAsB,EAAE,MAAM,CAAC;GACxD,CAAA;GACL,wBACC,oBAAC,UAAD;IACE,MAAK;IACL,aAAU;IACV,WAAU;IACV,SAAS;cAER,EAAE,kCAAkC,iCAAiC,EAAE,MAAM,CAAC;GACzE,CAAA;GAEV,oBAAC,OAAD;IAAK,WAAU;cACZ,QAAQ,KAAK,WACZ,qBAAC,QAAD;KAEE,MAAK;KACL,aAAW,eAAe,eAAe,OAAO,EAAE;KAClD,SAAS,OAAO;KAChB,UAAU;KACV,eAAe,IAAI,MAAM;eAN3B,CAQG,cAAc,oBAAC,SAAD,CAAU,CAAA,GACxB,OAAO,KACF;OATD,OAAO,EASN,CACT;GACE,CAAA;GAEJ,YAAY,gBACX,oBAAC,eAAD;IACE,OAAO,WAAW,aAAa,SAAS,WAAW;IACnD,aAAa,WAAW,aAAa,eAAe,KAAA;IACpD,cAAc,WAAW,aAAa,gBAAgB,WAAW;IACjE,aAAa,WAAW,aAAa,eAAe,EAAE,iBAAiB,QAAQ;IAC/E,gBAAgB,WAAW;IACf;IACZ,iBAAiB,KAAK,OAAO,UAAU;IACvC,gBAAgB,cAAc,IAAI;GACnC,CAAA;GAGF,SAAS,QACR,oBAAC,YAAD;IACE,aAAa,QAAQ,cAAc,eAAe,EAAE,iBAAiB,QAAQ;IAC7E,cAAc,QAAQ;IACtB,aAAa,QAAQ,cAAc,eAAe,KAAA;IAClD,UAAU,QAAQ;IAClB,WAAW,iBAAiB;IAC5B,UAAU,QAAQ;IAClB,QAAQ,QAAQ;IAChB,eAAe,WAAW,IAAI;IAC9B,iBAAiB;KACf,WAAW,IAAI;KACf,YAAY;IACd;IACA,WAAW,QAAQ,aAAa;IAChC,aAAa,QAAQ,cAAc,gBAAgB,QAAQ;IAC3D,OAAO,QAAQ,cAAc,SAAS,QAAQ;IAC9C,OAAO,QAAQ,cAAc,KAAA;GAC9B,CAAA;EAEA;;AAET"}
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { NumberFormat } from '../../../types/index.js';
2
+ import { NumberFormat } from '../../../types/generated.js';
3
3
  import { TableColumn } from '../../types.js';
4
4
  /** Shared numeric cell body for the money and number columns. */
5
5
  export declare function NumericCell({ column, copyable, format, value, }: {
@@ -1 +1 @@
1
- {"version":3,"file":"numeric-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/numeric-cell.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { useLocale } from \"@lattice-php/lattice/i18n\";\nimport type { NumberFormat } from \"@lattice-php/lattice/types\";\nimport { formatNumber } from \"@lattice-php/lattice/format/number\";\nimport { numericValue } from \"@lattice-php/lattice/format/numeric\";\nimport { formatCell } from \"@lattice-php/lattice/table/lib/format\";\nimport type { TableColumn } from \"@lattice-php/lattice/table/types\";\nimport { CopyableCell } from \"./copyable-cell\";\n\n/** Shared numeric cell body for the money and number columns. */\nexport function NumericCell({\n column,\n copyable,\n format,\n value,\n}: {\n column: TableColumn;\n copyable?: boolean | null;\n format: NumberFormat;\n value: unknown;\n}): ReactNode {\n const { locale } = useLocale();\n\n if (numericValue(value) === null) {\n return <span>{formatCell(value, column)}</span>;\n }\n\n return (\n <CopyableCell column={column} copyable={copyable} value={String(value)}>\n <span className=\"tabular-nums\">{formatNumber(value, format, locale)}</span>\n </CopyableCell>\n );\n}\n"],"mappings":";;;;;;;;AAUA,SAAgB,YAAY,EAC1B,QACA,UACA,QACA,SAMY;CACZ,MAAM,EAAE,WAAW,UAAU;CAE7B,IAAI,aAAa,KAAK,MAAM,MAC1B,OAAO,oBAAC,QAAD,EAAA,UAAO,WAAW,OAAO,MAAM,EAAQ,CAAA;CAGhD,OACE,oBAAC,cAAD;EAAsB;EAAkB;EAAU,OAAO,OAAO,KAAK;YACnE,oBAAC,QAAD;GAAM,WAAU;aAAgB,aAAa,OAAO,QAAQ,MAAM;EAAQ,CAAA;CAC9D,CAAA;AAElB"}
1
+ {"version":3,"file":"numeric-cell.js","names":[],"sources":["../../../../resources/js/table/components/cells/numeric-cell.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { useLocale } from \"@lattice-php/lattice/i18n\";\nimport type { NumberFormat } from \"@lattice-php/lattice/types/generated\";\nimport { formatNumber } from \"@lattice-php/lattice/format/number\";\nimport { numericValue } from \"@lattice-php/lattice/format/numeric\";\nimport { formatCell } from \"@lattice-php/lattice/table/lib/format\";\nimport type { TableColumn } from \"@lattice-php/lattice/table/types\";\nimport { CopyableCell } from \"./copyable-cell\";\n\n/** Shared numeric cell body for the money and number columns. */\nexport function NumericCell({\n column,\n copyable,\n format,\n value,\n}: {\n column: TableColumn;\n copyable?: boolean | null;\n format: NumberFormat;\n value: unknown;\n}): ReactNode {\n const { locale } = useLocale();\n\n if (numericValue(value) === null) {\n return <span>{formatCell(value, column)}</span>;\n }\n\n return (\n <CopyableCell column={column} copyable={copyable} value={String(value)}>\n <span className=\"tabular-nums\">{formatNumber(value, format, locale)}</span>\n </CopyableCell>\n );\n}\n"],"mappings":";;;;;;;;AAUA,SAAgB,YAAY,EAC1B,QACA,UACA,QACA,SAMY;CACZ,MAAM,EAAE,WAAW,UAAU;CAE7B,IAAI,aAAa,KAAK,MAAM,MAC1B,OAAO,oBAAC,QAAD,EAAA,UAAO,WAAW,OAAO,MAAM,EAAQ,CAAA;CAGhD,OACE,oBAAC,cAAD;EAAsB;EAAkB;EAAU,OAAO,OAAO,KAAK;YACnE,oBAAC,QAAD;GAAM,WAAU;aAAgB,aAAa,OAAO,QAAQ,MAAM;EAAQ,CAAA;CAC9D,CAAA;AAElB"}
@@ -1,3 +1,4 @@
1
+ import { actionLabel } from "../../action/lib/action-label.js";
1
2
  //#region resources/js/table/lib/bulk.ts
2
3
  function getBulkActions(actions) {
3
4
  return (actions ?? []).flatMap((node) => {
@@ -6,7 +7,7 @@ function getBulkActions(actions) {
6
7
  if (!props.endpoint) return [];
7
8
  return [{
8
9
  id: node.id ?? "",
9
- label: props.label ?? "Run action",
10
+ label: actionLabel(node),
10
11
  method: props.method ?? "post",
11
12
  endpoint: props.endpoint,
12
13
  ref: props.ref ?? "",
@@ -1 +1 @@
1
- {"version":3,"file":"bulk.js","names":[],"sources":["../../../resources/js/table/lib/bulk.ts"],"sourcesContent":["import type { Method } from \"@inertiajs/core\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport type { Action, ButtonVariant } from \"@lattice-php/lattice/types/generated\";\nimport type { ActionNode } from \"@lattice-php/lattice/table/types\";\n\nexport type BulkAction = {\n id: string;\n label: string;\n method: Method;\n endpoint: string;\n ref: string;\n variant: ButtonVariant;\n confirmation: Action[\"confirmation\"];\n form: Node | null;\n modalSide: Action[\"modalSide\"];\n modalWidth: Action[\"modalWidth\"];\n};\n\nexport function getBulkActions(actions: ActionNode[] | undefined): BulkAction[] {\n return (actions ?? []).flatMap((node): BulkAction[] => {\n if (node.type === \"action.group\") {\n return [];\n }\n\n const props = node.props;\n\n if (!props.endpoint) {\n return [];\n }\n\n return [\n {\n id: node.id ?? \"\",\n label: props.label ?? \"Run action\",\n method: props.method ?? \"post\",\n endpoint: props.endpoint,\n ref: props.ref ?? \"\",\n variant: props.variant ?? \"default\",\n confirmation: props.confirmation,\n form: props.form,\n modalSide: props.modalSide,\n modalWidth: props.modalWidth,\n },\n ];\n });\n}\n"],"mappings":";AAkBA,SAAgB,eAAe,SAAiD;CAC9E,QAAQ,WAAW,CAAC,GAAG,SAAS,SAAuB;EACrD,IAAI,KAAK,SAAS,gBAChB,OAAO,CAAC;EAGV,MAAM,QAAQ,KAAK;EAEnB,IAAI,CAAC,MAAM,UACT,OAAO,CAAC;EAGV,OAAO,CACL;GACE,IAAI,KAAK,MAAM;GACf,OAAO,MAAM,SAAS;GACtB,QAAQ,MAAM,UAAU;GACxB,UAAU,MAAM;GAChB,KAAK,MAAM,OAAO;GAClB,SAAS,MAAM,WAAW;GAC1B,cAAc,MAAM;GACpB,MAAM,MAAM;GACZ,WAAW,MAAM;GACjB,YAAY,MAAM;EACpB,CACF;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"bulk.js","names":[],"sources":["../../../resources/js/table/lib/bulk.ts"],"sourcesContent":["import type { Method } from \"@inertiajs/core\";\nimport type { Node } from \"@lattice-php/lattice/core/types\";\nimport type { Action, ButtonVariant } from \"@lattice-php/lattice/types/generated\";\nimport type { ActionNode } from \"@lattice-php/lattice/table/types\";\nimport { actionLabel } from \"@lattice-php/lattice/action/lib/action-label\";\n\nexport type BulkAction = {\n id: string;\n label: string;\n method: Method;\n endpoint: string;\n ref: string;\n variant: ButtonVariant;\n confirmation: Action[\"confirmation\"];\n form: Node | null;\n modalSide: Action[\"modalSide\"];\n modalWidth: Action[\"modalWidth\"];\n};\n\nexport function getBulkActions(actions: ActionNode[] | undefined): BulkAction[] {\n return (actions ?? []).flatMap((node): BulkAction[] => {\n if (node.type === \"action.group\") {\n return [];\n }\n\n const props = node.props;\n\n if (!props.endpoint) {\n return [];\n }\n\n return [\n {\n id: node.id ?? \"\",\n label: actionLabel(node),\n method: props.method ?? \"post\",\n endpoint: props.endpoint,\n ref: props.ref ?? \"\",\n variant: props.variant ?? \"default\",\n confirmation: props.confirmation,\n form: props.form,\n modalSide: props.modalSide,\n modalWidth: props.modalWidth,\n },\n ];\n });\n}\n"],"mappings":";;AAmBA,SAAgB,eAAe,SAAiD;CAC9E,QAAQ,WAAW,CAAC,GAAG,SAAS,SAAuB;EACrD,IAAI,KAAK,SAAS,gBAChB,OAAO,CAAC;EAGV,MAAM,QAAQ,KAAK;EAEnB,IAAI,CAAC,MAAM,UACT,OAAO,CAAC;EAGV,OAAO,CACL;GACE,IAAI,KAAK,MAAM;GACf,OAAO,YAAY,IAAI;GACvB,QAAQ,MAAM,UAAU;GACxB,UAAU,MAAM;GAChB,KAAK,MAAM,OAAO;GAClB,SAAS,MAAM,WAAW;GAC1B,cAAc,MAAM;GACpB,MAAM,MAAM;GACZ,WAAW,MAAM;GACjB,YAAY,MAAM;EACpB,CACF;CACF,CAAC;AACH"}
@@ -1,6 +1,6 @@
1
1
  export { normalizeCallout, onCallout } from './callout.js';
2
2
  export type { Callout } from './callout.js';
3
3
  export { Toaster } from './toaster.js';
4
- export { isVariant, normalizeToastMessage, onToast } from './toast.js';
4
+ export { onToast } from './toast.js';
5
5
  export type { ToastMessage, Variant } from './toast.js';
6
6
  export { variantStyles } from './variant-styles.js';
@@ -1,5 +1,5 @@
1
- import { isVariant, normalizeToastMessage, onToast } from "./toast.js";
1
+ import { onToast } from "./toast.js";
2
2
  import { normalizeCallout, onCallout } from "./callout.js";
3
3
  import { variantStyles } from "./variant-styles.js";
4
4
  import { Toaster } from "./toaster.js";
5
- export { Toaster, isVariant, normalizeCallout, normalizeToastMessage, onCallout, onToast, variantStyles };
5
+ export { Toaster, normalizeCallout, onCallout, onToast, variantStyles };
@@ -461,7 +461,7 @@ export type Confirmation = {
461
461
  readonly cancelLabel: string | null;
462
462
  readonly confirmLabel: string | null;
463
463
  readonly description: string | null;
464
- readonly title: string;
464
+ readonly title: string | null;
465
465
  };
466
466
  export type DataList = {
467
467
  dataEndpoint: string | null;
package/dist/ui/modal.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { LATTICE_EVENT } from "../core/event-names.js";
2
+ import { useT } from "../i18n/instance.js";
2
3
  import { Dialog, DialogContent, DialogHeader } from "./dialog.js";
3
4
  import { useEffect, useRef, useState } from "react";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -8,7 +9,8 @@ function matchesModal(event, modal) {
8
9
  return target == null || target === modal;
9
10
  }
10
11
  var ModalComponent = ({ children, node }) => {
11
- const title = node.props.title ?? "Dialog";
12
+ const { t } = useT("lattice");
13
+ const title = node.props.title ?? t("common.dialog", "Dialog");
12
14
  const description = node.props.description;
13
15
  const closeLabel = node.props.closeLabel;
14
16
  const [isOpen, setIsOpen] = useState(node.props.open === true);
@@ -1 +1 @@
1
- {"version":3,"file":"modal.js","names":[],"sources":["../../resources/js/ui/modal.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { Dialog, DialogContent, DialogHeader } from \"@lattice-php/lattice/ui/dialog\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\n\ntype ModalEvent = CustomEvent<{\n modal: string | null;\n}>;\n\nfunction matchesModal(event: Event, modal: string): boolean {\n const target = (event as ModalEvent).detail?.modal;\n\n return target == null || target === modal;\n}\n\nconst ModalComponent: RendererComponent<\"modal\"> = ({ children, node }) => {\n const title = node.props.title ?? \"Dialog\";\n const description = node.props.description;\n const closeLabel = node.props.closeLabel;\n const [isOpen, setIsOpen] = useState(node.props.open === true);\n const openerRef = useRef<HTMLElement | null>(null);\n const wasOpenRef = useRef(isOpen);\n\n // Honour server-driven open changes across re-renders, not just on mount. One\n // way on purpose: closing stays user/closeModal-driven so it never fights a\n // manual close, and the dep keeps it from re-firing while open stays true.\n useEffect(() => {\n if (node.props.open === true) {\n setIsOpen(true);\n }\n }, [node.props.open]);\n\n useEffect(() => {\n function open(event: Event): void {\n if (node.id && matchesModal(event, node.id)) {\n openerRef.current =\n document.activeElement instanceof HTMLElement ? document.activeElement : null;\n setIsOpen(true);\n }\n }\n\n function close(event: Event): void {\n if (!node.id || matchesModal(event, node.id)) {\n setIsOpen(false);\n }\n }\n\n window.addEventListener(LATTICE_EVENT.openModal, open);\n window.addEventListener(LATTICE_EVENT.closeModal, close);\n\n return () => {\n window.removeEventListener(LATTICE_EVENT.openModal, open);\n window.removeEventListener(LATTICE_EVENT.closeModal, close);\n };\n }, [node.id]);\n\n // Radix only restores focus to a `DialogTrigger`-registered element, and this\n // modal is opened imperatively rather than through one. Own the restore\n // ourselves instead: whatever had focus when the modal opened gets it back\n // once the closing dialog has finished unmounting.\n useEffect(() => {\n if (wasOpenRef.current && !isOpen) {\n const opener = openerRef.current;\n\n if (opener) {\n requestAnimationFrame(() => opener.focus());\n }\n }\n\n wasOpenRef.current = isOpen;\n }, [isOpen]);\n\n return (\n <Dialog open={isOpen} onOpenChange={setIsOpen}>\n <DialogContent\n {...(description ? {} : { \"aria-describedby\": undefined })}\n placement={node.props.side ?? \"center\"}\n width={node.props.width}\n >\n <DialogHeader closeLabel={closeLabel} description={description} title={title} />\n <div className=\"mt-6 space-y-6\">{children}</div>\n </DialogContent>\n </Dialog>\n );\n};\n\nexport default ModalComponent;\n"],"mappings":";;;;;AASA,SAAS,aAAa,OAAc,OAAwB;CAC1D,MAAM,SAAU,MAAqB,QAAQ;CAE7C,OAAO,UAAU,QAAQ,WAAW;AACtC;AAEA,IAAM,kBAA8C,EAAE,UAAU,WAAW;CACzE,MAAM,QAAQ,KAAK,MAAM,SAAS;CAClC,MAAM,cAAc,KAAK,MAAM;CAC/B,MAAM,aAAa,KAAK,MAAM;CAC9B,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK,MAAM,SAAS,IAAI;CAC7D,MAAM,YAAY,OAA2B,IAAI;CACjD,MAAM,aAAa,OAAO,MAAM;CAKhC,gBAAgB;EACd,IAAI,KAAK,MAAM,SAAS,MACtB,UAAU,IAAI;CAElB,GAAG,CAAC,KAAK,MAAM,IAAI,CAAC;CAEpB,gBAAgB;EACd,SAAS,KAAK,OAAoB;GAChC,IAAI,KAAK,MAAM,aAAa,OAAO,KAAK,EAAE,GAAG;IAC3C,UAAU,UACR,SAAS,yBAAyB,cAAc,SAAS,gBAAgB;IAC3E,UAAU,IAAI;GAChB;EACF;EAEA,SAAS,MAAM,OAAoB;GACjC,IAAI,CAAC,KAAK,MAAM,aAAa,OAAO,KAAK,EAAE,GACzC,UAAU,KAAK;EAEnB;EAEA,OAAO,iBAAiB,cAAc,WAAW,IAAI;EACrD,OAAO,iBAAiB,cAAc,YAAY,KAAK;EAEvD,aAAa;GACX,OAAO,oBAAoB,cAAc,WAAW,IAAI;GACxD,OAAO,oBAAoB,cAAc,YAAY,KAAK;EAC5D;CACF,GAAG,CAAC,KAAK,EAAE,CAAC;CAMZ,gBAAgB;EACd,IAAI,WAAW,WAAW,CAAC,QAAQ;GACjC,MAAM,SAAS,UAAU;GAEzB,IAAI,QACF,4BAA4B,OAAO,MAAM,CAAC;EAE9C;EAEA,WAAW,UAAU;CACvB,GAAG,CAAC,MAAM,CAAC;CAEX,OACE,oBAAC,QAAD;EAAQ,MAAM;EAAQ,cAAc;YAClC,qBAAC,eAAD;GACE,GAAK,cAAc,CAAC,IAAI,EAAE,oBAAoB,KAAA,EAAU;GACxD,WAAW,KAAK,MAAM,QAAQ;GAC9B,OAAO,KAAK,MAAM;aAHpB,CAKE,oBAAC,cAAD;IAA0B;IAAyB;IAAoB;GAAQ,CAAA,GAC/E,oBAAC,OAAD;IAAK,WAAU;IAAkB;GAAc,CAAA,CAClC;;CACT,CAAA;AAEZ"}
1
+ {"version":3,"file":"modal.js","names":[],"sources":["../../resources/js/ui/modal.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { Dialog, DialogContent, DialogHeader } from \"@lattice-php/lattice/ui/dialog\";\nimport type { RendererComponent } from \"@lattice-php/lattice/core/types\";\nimport { LATTICE_EVENT } from \"@lattice-php/lattice/core/event-names\";\nimport { useT } from \"@lattice-php/lattice/i18n\";\n\ntype ModalEvent = CustomEvent<{\n modal: string | null;\n}>;\n\nfunction matchesModal(event: Event, modal: string): boolean {\n const target = (event as ModalEvent).detail?.modal;\n\n return target == null || target === modal;\n}\n\nconst ModalComponent: RendererComponent<\"modal\"> = ({ children, node }) => {\n const { t } = useT(\"lattice\");\n const title = node.props.title ?? t(\"common.dialog\", \"Dialog\");\n const description = node.props.description;\n const closeLabel = node.props.closeLabel;\n const [isOpen, setIsOpen] = useState(node.props.open === true);\n const openerRef = useRef<HTMLElement | null>(null);\n const wasOpenRef = useRef(isOpen);\n\n // Honour server-driven open changes across re-renders, not just on mount. One\n // way on purpose: closing stays user/closeModal-driven so it never fights a\n // manual close, and the dep keeps it from re-firing while open stays true.\n useEffect(() => {\n if (node.props.open === true) {\n setIsOpen(true);\n }\n }, [node.props.open]);\n\n useEffect(() => {\n function open(event: Event): void {\n if (node.id && matchesModal(event, node.id)) {\n openerRef.current =\n document.activeElement instanceof HTMLElement ? document.activeElement : null;\n setIsOpen(true);\n }\n }\n\n function close(event: Event): void {\n if (!node.id || matchesModal(event, node.id)) {\n setIsOpen(false);\n }\n }\n\n window.addEventListener(LATTICE_EVENT.openModal, open);\n window.addEventListener(LATTICE_EVENT.closeModal, close);\n\n return () => {\n window.removeEventListener(LATTICE_EVENT.openModal, open);\n window.removeEventListener(LATTICE_EVENT.closeModal, close);\n };\n }, [node.id]);\n\n // Radix only restores focus to a `DialogTrigger`-registered element, and this\n // modal is opened imperatively rather than through one. Own the restore\n // ourselves instead: whatever had focus when the modal opened gets it back\n // once the closing dialog has finished unmounting.\n useEffect(() => {\n if (wasOpenRef.current && !isOpen) {\n const opener = openerRef.current;\n\n if (opener) {\n requestAnimationFrame(() => opener.focus());\n }\n }\n\n wasOpenRef.current = isOpen;\n }, [isOpen]);\n\n return (\n <Dialog open={isOpen} onOpenChange={setIsOpen}>\n <DialogContent\n {...(description ? {} : { \"aria-describedby\": undefined })}\n placement={node.props.side ?? \"center\"}\n width={node.props.width}\n >\n <DialogHeader closeLabel={closeLabel} description={description} title={title} />\n <div className=\"mt-6 space-y-6\">{children}</div>\n </DialogContent>\n </Dialog>\n );\n};\n\nexport default ModalComponent;\n"],"mappings":";;;;;;AAUA,SAAS,aAAa,OAAc,OAAwB;CAC1D,MAAM,SAAU,MAAqB,QAAQ;CAE7C,OAAO,UAAU,QAAQ,WAAW;AACtC;AAEA,IAAM,kBAA8C,EAAE,UAAU,WAAW;CACzE,MAAM,EAAE,MAAM,KAAK,SAAS;CAC5B,MAAM,QAAQ,KAAK,MAAM,SAAS,EAAE,iBAAiB,QAAQ;CAC7D,MAAM,cAAc,KAAK,MAAM;CAC/B,MAAM,aAAa,KAAK,MAAM;CAC9B,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK,MAAM,SAAS,IAAI;CAC7D,MAAM,YAAY,OAA2B,IAAI;CACjD,MAAM,aAAa,OAAO,MAAM;CAKhC,gBAAgB;EACd,IAAI,KAAK,MAAM,SAAS,MACtB,UAAU,IAAI;CAElB,GAAG,CAAC,KAAK,MAAM,IAAI,CAAC;CAEpB,gBAAgB;EACd,SAAS,KAAK,OAAoB;GAChC,IAAI,KAAK,MAAM,aAAa,OAAO,KAAK,EAAE,GAAG;IAC3C,UAAU,UACR,SAAS,yBAAyB,cAAc,SAAS,gBAAgB;IAC3E,UAAU,IAAI;GAChB;EACF;EAEA,SAAS,MAAM,OAAoB;GACjC,IAAI,CAAC,KAAK,MAAM,aAAa,OAAO,KAAK,EAAE,GACzC,UAAU,KAAK;EAEnB;EAEA,OAAO,iBAAiB,cAAc,WAAW,IAAI;EACrD,OAAO,iBAAiB,cAAc,YAAY,KAAK;EAEvD,aAAa;GACX,OAAO,oBAAoB,cAAc,WAAW,IAAI;GACxD,OAAO,oBAAoB,cAAc,YAAY,KAAK;EAC5D;CACF,GAAG,CAAC,KAAK,EAAE,CAAC;CAMZ,gBAAgB;EACd,IAAI,WAAW,WAAW,CAAC,QAAQ;GACjC,MAAM,SAAS,UAAU;GAEzB,IAAI,QACF,4BAA4B,OAAO,MAAM,CAAC;EAE9C;EAEA,WAAW,UAAU;CACvB,GAAG,CAAC,MAAM,CAAC;CAEX,OACE,oBAAC,QAAD;EAAQ,MAAM;EAAQ,cAAc;YAClC,qBAAC,eAAD;GACE,GAAK,cAAc,CAAC,IAAI,EAAE,oBAAoB,KAAA,EAAU;GACxD,WAAW,KAAK,MAAM,QAAQ;GAC9B,OAAO,KAAK,MAAM;aAHpB,CAKE,oBAAC,cAAD;IAA0B;IAAyB;IAAoB;GAAQ,CAAA,GAC/E,oBAAC,OAAD;IAAK,WAAU;IAAkB;GAAc,CAAA,CAClC;;CACT,CAAA;AAEZ"}
@@ -1 +1 @@
1
- import{i as e,t}from"./react-B8IZ02wI.js";import{t as n}from"./jsx-runtime-Drll_-DD.js";import{t as r}from"./use-effect-dispatcher-D1wPPwHj.js";import{B as i,L as a,z as o}from"../lattice.js";import{useEcho as s,useEchoPresence as c,useEchoPublic as l}from"./dist-PaT1gYi_.js";var u=e(t(),1);function d(e,t,n){return e.map(e=>f(e,t,n))}function f(e,t,n){if(e.type!==`toast`)return e;let r=e.props;if(typeof r!=`object`||!r)return e;let a=r.message;return o(a)?{...e,props:{...r,message:i(a,t,n)}}:e}var p=n();function m(e){let{t}=a(`lattice`),n=r();return(0,u.useCallback)(r=>{let i=typeof r==`object`&&r?r:{};n(d(e.effects,i,t))},[n,e,t])}function h({listener:e}){return l(e.channel,e.events,m(e)),null}function g({listener:e}){return s(e.channel,e.events,m(e)),null}function _({listener:e}){return c(e.channel,e.events,m(e)),null}function v({listener:e}){switch(e.visibility){case`private`:return(0,p.jsx)(g,{listener:e});case`presence`:return(0,p.jsx)(_,{listener:e});default:return(0,p.jsx)(h,{listener:e})}}function y({listeners:e}){return(0,p.jsx)(p.Fragment,{children:e.map((e,t)=>(0,p.jsx)(v,{listener:e},`${e.visibility}:${e.channel}:${t}`))})}export{y as default};
1
+ import{i as e,t}from"./react-B8IZ02wI.js";import{t as n}from"./jsx-runtime-Drll_-DD.js";import{t as r}from"./use-effect-dispatcher-EVZxmfoo.js";import{B as i,L as a,z as o}from"../lattice.js";import{useEcho as s,useEchoPresence as c,useEchoPublic as l}from"./dist-PaT1gYi_.js";var u=e(t(),1);function d(e,t,n){return e.map(e=>f(e,t,n))}function f(e,t,n){if(e.type!==`toast`)return e;let r=e.props;if(typeof r!=`object`||!r)return e;let a=r.message;return o(a)?{...e,props:{...r,message:i(a,t,n)}}:e}var p=n();function m(e){let{t}=a(`lattice`),n=r();return(0,u.useCallback)(r=>{let i=typeof r==`object`&&r?r:{};n(d(e.effects,i,t))},[n,e,t])}function h({listener:e}){return l(e.channel,e.events,m(e)),null}function g({listener:e}){return s(e.channel,e.events,m(e)),null}function _({listener:e}){return c(e.channel,e.events,m(e)),null}function v({listener:e}){switch(e.visibility){case`private`:return(0,p.jsx)(g,{listener:e});case`presence`:return(0,p.jsx)(_,{listener:e});default:return(0,p.jsx)(h,{listener:e})}}function y({listeners:e}){return(0,p.jsx)(p.Fragment,{children:e.map((e,t)=>(0,p.jsx)(v,{listener:e},`${e.visibility}:${e.channel}:${t}`))})}export{y as default};