@panneau/lists 5.0.0-alpha.2 → 5.0.0-alpha.21

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 (165) hide show
  1. package/README.md +17 -15
  2. package/dist/ItemDetails.css +50 -0
  3. package/dist/ItemDetails.d.ts +27 -0
  4. package/dist/ItemDetails.d.ts.map +1 -0
  5. package/dist/ItemDetails.js +134 -0
  6. package/dist/ItemDetails.js.map +1 -0
  7. package/dist/ItemDetails.module.js +20 -0
  8. package/dist/ItemDetails.module.js.map +1 -0
  9. package/dist/List.d.ts +3 -3
  10. package/dist/List.d.ts.map +1 -1
  11. package/dist/List.js +31 -10
  12. package/dist/List.js.map +1 -1
  13. package/dist/ListSkeleton.d.ts +19 -0
  14. package/dist/ListSkeleton.d.ts.map +1 -0
  15. package/dist/ListSkeleton.js +115 -0
  16. package/dist/ListSkeleton.js.map +1 -0
  17. package/dist/ListView.d.ts +73 -8
  18. package/dist/ListView.d.ts.map +1 -1
  19. package/dist/ListView.js +616 -218
  20. package/dist/ListView.js.map +1 -1
  21. package/dist/actions/ActionButton.d.ts +8 -2
  22. package/dist/actions/ActionButton.d.ts.map +1 -1
  23. package/dist/actions/ActionButton.js +98 -26
  24. package/dist/actions/ActionButton.js.map +1 -1
  25. package/dist/actions/Actions.css +16 -38
  26. package/dist/actions/Actions.module.js +6 -6
  27. package/dist/actions/Actions.module.js.map +1 -1
  28. package/dist/actions/ConfirmDialog.d.ts +20 -4
  29. package/dist/actions/ConfirmDialog.d.ts.map +1 -1
  30. package/dist/actions/ConfirmDialog.js +110 -92
  31. package/dist/actions/ConfirmDialog.js.map +1 -1
  32. package/dist/actions/RowActions.d.ts +25 -9
  33. package/dist/actions/RowActions.d.ts.map +1 -1
  34. package/dist/actions/RowActions.js +151 -80
  35. package/dist/actions/RowActions.js.map +1 -1
  36. package/dist/actions/actions.d.ts +5 -4
  37. package/dist/actions/actions.d.ts.map +1 -1
  38. package/dist/actions/actions.js +7 -14
  39. package/dist/actions/actions.js.map +1 -1
  40. package/dist/actions/fit.d.ts +25 -0
  41. package/dist/actions/fit.d.ts.map +1 -0
  42. package/dist/actions/fit.js +197 -0
  43. package/dist/actions/fit.js.map +1 -0
  44. package/dist/actions/icons.d.ts +5 -0
  45. package/dist/actions/icons.d.ts.map +1 -1
  46. package/dist/actions/icons.js +15 -1
  47. package/dist/actions/icons.js.map +1 -1
  48. package/dist/columns.d.ts +10 -0
  49. package/dist/columns.d.ts.map +1 -0
  50. package/dist/columns.js +25 -0
  51. package/dist/columns.js.map +1 -0
  52. package/dist/cx.js.map +1 -1
  53. package/dist/displays/Displays.css +48 -0
  54. package/dist/displays/Displays.module.js +18 -2
  55. package/dist/displays/Displays.module.js.map +1 -1
  56. package/dist/displays/displays.d.ts +62 -6
  57. package/dist/displays/displays.d.ts.map +1 -1
  58. package/dist/displays/displays.js +1151 -89
  59. package/dist/displays/displays.js.map +1 -1
  60. package/dist/filters/Filters.css +25 -11
  61. package/dist/filters/Filters.d.ts +1 -1
  62. package/dist/filters/Filters.js.map +1 -1
  63. package/dist/filters/Filters.module.js +5 -1
  64. package/dist/filters/Filters.module.js.map +1 -1
  65. package/dist/filters/controls.d.ts +1 -1
  66. package/dist/filters/controls.d.ts.map +1 -1
  67. package/dist/filters/controls.js +57 -35
  68. package/dist/filters/controls.js.map +1 -1
  69. package/dist/filters/format.d.ts +1 -1
  70. package/dist/filters/format.js.map +1 -1
  71. package/dist/images.d.ts +7 -0
  72. package/dist/images.d.ts.map +1 -0
  73. package/dist/images.js +39 -0
  74. package/dist/images.js.map +1 -0
  75. package/dist/index.d.ts +22 -18
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +7 -3
  78. package/dist/inline/Inline.css +58 -0
  79. package/dist/inline/Inline.module.js +20 -0
  80. package/dist/inline/Inline.module.js.map +1 -0
  81. package/dist/inline/InlineCell.d.ts +29 -0
  82. package/dist/inline/InlineCell.d.ts.map +1 -0
  83. package/dist/inline/InlineCell.js +490 -0
  84. package/dist/inline/InlineCell.js.map +1 -0
  85. package/dist/inline/editable.d.ts +12 -0
  86. package/dist/inline/editable.d.ts.map +1 -0
  87. package/dist/inline/editable.js +29 -0
  88. package/dist/inline/editable.js.map +1 -0
  89. package/dist/layouts/CalendarLayout.css +153 -0
  90. package/dist/layouts/CalendarLayout.d.ts +9 -0
  91. package/dist/layouts/CalendarLayout.d.ts.map +1 -0
  92. package/dist/layouts/CalendarLayout.js +303 -0
  93. package/dist/layouts/CalendarLayout.js.map +1 -0
  94. package/dist/layouts/CalendarLayout.module.js +28 -0
  95. package/dist/layouts/CalendarLayout.module.js.map +1 -0
  96. package/dist/layouts/CardsLayout.css +5 -0
  97. package/dist/layouts/CardsLayout.d.ts +2 -2
  98. package/dist/layouts/CardsLayout.d.ts.map +1 -1
  99. package/dist/layouts/CardsLayout.js +92 -91
  100. package/dist/layouts/CardsLayout.js.map +1 -1
  101. package/dist/layouts/CardsLayout.module.js.map +1 -1
  102. package/dist/layouts/GalleryLayout.css +87 -0
  103. package/dist/layouts/GalleryLayout.d.ts +8 -0
  104. package/dist/layouts/GalleryLayout.d.ts.map +1 -0
  105. package/dist/layouts/GalleryLayout.js +152 -0
  106. package/dist/layouts/GalleryLayout.js.map +1 -0
  107. package/dist/layouts/GalleryLayout.module.js +26 -0
  108. package/dist/layouts/GalleryLayout.module.js.map +1 -0
  109. package/dist/layouts/ItemTitle.d.ts +3 -1
  110. package/dist/layouts/ItemTitle.d.ts.map +1 -1
  111. package/dist/layouts/ItemTitle.js +12 -8
  112. package/dist/layouts/ItemTitle.js.map +1 -1
  113. package/dist/layouts/TableLayout.css +56 -0
  114. package/dist/layouts/TableLayout.d.ts +5 -4
  115. package/dist/layouts/TableLayout.d.ts.map +1 -1
  116. package/dist/layouts/TableLayout.js +171 -101
  117. package/dist/layouts/TableLayout.js.map +1 -1
  118. package/dist/layouts/TableLayout.module.js +8 -4
  119. package/dist/layouts/TableLayout.module.js.map +1 -1
  120. package/dist/layouts/builtIn.d.ts +2 -2
  121. package/dist/layouts/builtIn.d.ts.map +1 -1
  122. package/dist/layouts/builtIn.js +6 -2
  123. package/dist/layouts/builtIn.js.map +1 -1
  124. package/dist/layouts/calendarDays.d.ts +14 -0
  125. package/dist/layouts/calendarDays.d.ts.map +1 -0
  126. package/dist/layouts/calendarDays.js +44 -0
  127. package/dist/layouts/calendarDays.js.map +1 -0
  128. package/dist/plugin.d.ts +1 -1
  129. package/dist/plugin.js.map +1 -1
  130. package/dist/query.d.ts +4 -3
  131. package/dist/query.d.ts.map +1 -1
  132. package/dist/query.js +15 -4
  133. package/dist/query.js.map +1 -1
  134. package/dist/selection.d.ts +1 -1
  135. package/dist/selection.js.map +1 -1
  136. package/dist/toolbar/ColumnMenu.d.ts +17 -0
  137. package/dist/toolbar/ColumnMenu.d.ts.map +1 -0
  138. package/dist/toolbar/ColumnMenu.js +193 -0
  139. package/dist/toolbar/ColumnMenu.js.map +1 -0
  140. package/dist/toolbar/LayoutSwitch.d.ts.map +1 -1
  141. package/dist/toolbar/LayoutSwitch.js +73 -55
  142. package/dist/toolbar/LayoutSwitch.js.map +1 -1
  143. package/dist/toolbar/Pagination.d.ts +33 -0
  144. package/dist/toolbar/Pagination.d.ts.map +1 -1
  145. package/dist/toolbar/Pagination.js +282 -42
  146. package/dist/toolbar/Pagination.js.map +1 -1
  147. package/dist/toolbar/SearchField.js.map +1 -1
  148. package/dist/toolbar/SortSelect.d.ts +1 -1
  149. package/dist/toolbar/SortSelect.js.map +1 -1
  150. package/dist/toolbar/Toolbar.css +36 -0
  151. package/dist/toolbar/Toolbar.module.js +12 -2
  152. package/dist/toolbar/Toolbar.module.js.map +1 -1
  153. package/dist/types.d.ts +69 -1
  154. package/dist/types.d.ts.map +1 -1
  155. package/dist/useDraft.js.map +1 -1
  156. package/dist/useListState.js.map +1 -1
  157. package/dist/useRenderValue.d.ts +10 -0
  158. package/dist/useRenderValue.d.ts.map +1 -0
  159. package/dist/useRenderValue.js +84 -0
  160. package/dist/useRenderValue.js.map +1 -0
  161. package/dist/values.d.ts +4 -1
  162. package/dist/values.d.ts.map +1 -1
  163. package/dist/values.js +6 -2
  164. package/dist/values.js.map +1 -1
  165. package/package.json +9 -9
@@ -1 +1 @@
1
- {"version":3,"file":"RowActions.js","names":["action","icons","Ellipsis","_c","styles"],"sources":["../../src/actions/RowActions.tsx"],"sourcesContent":["import { Ellipsis } from 'lucide-react';\n\nimport type { Action } from '@panneau/protocol';\nimport { IconButton, Menu, MenuItem, MenuTrigger, usePanneauIntl } from '@panneau/ui';\n\nimport { messages } from '../messages';\nimport type { ListItem } from '../types';\nimport { ActionButton } from './ActionButton';\nimport styles from './Actions.module.css';\nimport { getActionHref } from './actions';\nimport { type ActionIcons, getActionIcon } from './icons';\n\nexport interface RowActionsProps {\n item: ListItem;\n /** The label of the item, for the accessible names of its actions. */\n itemLabel: string;\n /** Actions shown as buttons. */\n actions: readonly Action[];\n /** Actions in the overflow menu. */\n menu: readonly Action[];\n /** Id of the action that is running on this item, if any. */\n pending: string | null;\n onRun: (action: Action) => void;\n /** Icons of actions by id, over the icon the action names. */\n icons?: ActionIcons | undefined;\n}\n\n/** The actions of a row: buttons, then an overflow menu. */\nexport function RowActions({\n item,\n itemLabel,\n actions,\n menu,\n pending,\n onRun,\n icons,\n}: RowActionsProps) {\n const intl = usePanneauIntl();\n return (\n <div className={styles.row}>\n {actions.map((action) => (\n <ActionButton\n key={action.id}\n action={action}\n icons={icons}\n href={getActionHref(action, item)}\n isPending={pending === action.id}\n isDisabled={pending !== null && pending !== action.id}\n aria-label={intl.formatMessage(messages.actionOnItem, {\n action: action.label,\n item: itemLabel,\n })}\n onPress={() => onRun(action)}\n />\n ))}\n {menu.length > 0 ? (\n <MenuTrigger>\n <IconButton\n icon={Ellipsis}\n size=\"sm\"\n label={intl.formatMessage(messages.itemActions, { item: itemLabel })}\n isPending={pending !== null && menu.some((action) => action.id === pending)}\n />\n <Menu\n placement=\"bottom end\"\n onAction={(key) => {\n const action = menu.find((candidate) => candidate.id === key);\n if (action !== undefined && getActionHref(action, item) === null) {\n onRun(action);\n }\n }}\n >\n {menu.map((action) => {\n const href = getActionHref(action, item);\n const icon = getActionIcon(action, icons);\n return (\n <MenuItem\n key={action.id}\n id={action.id}\n isDanger={action.destructive === true}\n {...(icon !== undefined ? { icon } : {})}\n {...(href !== null ? { href } : {})}\n >\n {action.label}\n </MenuItem>\n );\n })}\n </Menu>\n </MenuTrigger>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"RowActions.js","names":["Ellipsis","ReactNode","use","ItemAction","getActionLabel","Action","IconButton","Menu","MenuItem","MenuTrigger","usePanneauIntl","messages","ActionButton","styles","RowActionsFit","ActionIcons","getActionIcon","RowActionsProps","itemLabel","actions","menu","pending","onRun","action","icons","slots","primary","orderRowActions","all","filter","entry","index","list","findIndex","other","id","destructive","RowActions","t0","$","_c","t1","undefined","intl","level","t2","own","t3","t4","some","slot","find","slot_0","action_0","inMenu","length","Math","min","shown","slice","overflow","flatMap","slot_1","t5","action_1","formatMessage","actionOnItem","item","name","t6","href","button","placeholder","_temp","t7","itemActions","t8","t9","t10","action_2","t11","menuButton","row","map","slot_2","entry_0","key_0","entry_1","t12","action_3","key","t13","action_4","icon","content","_c","styles"],"sources":["../../src/actions/RowActions.tsx"],"sourcesContent":["import { Ellipsis } from 'lucide-react';\nimport { type ReactNode, use } from 'react';\n\nimport type { ItemAction } from '@panneau/core';\nimport { getActionLabel } from '@panneau/intl';\nimport type { Action } from '@panneau/protocol';\nimport { IconButton, Menu, MenuItem, MenuTrigger, usePanneauIntl } from '@panneau/ui';\n\nimport { messages } from '../messages';\nimport { ActionButton } from './ActionButton';\nimport styles from './Actions.module.css';\nimport { RowActionsFit } from './fit';\nimport { type ActionIcons, getActionIcon } from './icons';\n\nexport interface RowActionsProps {\n /** The label of the item, for the accessible names of its actions. */\n itemLabel: string;\n /** Actions placed in `row`, with their links (`selectItemActions()` of `@panneau/core`). */\n actions: readonly ItemAction[];\n /** Actions placed in `menu`: icons too while they fit, the first to go in the menu. */\n menu: readonly ItemAction[];\n /** Id of the action that is running on this item, if any. */\n pending: string | null;\n onRun: (action: Action) => void;\n /** Icons of actions by id, over the icon the action names. */\n icons?: ActionIcons | undefined;\n /**\n * The actions of every row of the list, in order (`orderRowActions()`): a row keeps the place\n * of those it doesn't have, so the actions of the rows line up. Without it, its own.\n */\n slots?: readonly ItemAction[] | undefined;\n /** The id of the main action of rows, which keeps its label (`show` or `edit`). */\n primary?: string | null | undefined;\n}\n\n/**\n * The actions of a row in their order: those placed in `row`, then those placed in `menu`, and\n * those that destroy last. The last ones are the first to go in the menu.\n */\nexport function orderRowActions(\n actions: readonly ItemAction[],\n menu: readonly ItemAction[],\n): ItemAction[] {\n const all = [...actions, ...menu].filter(\n (entry, index, list) =>\n list.findIndex((other) => other.action.id === entry.action.id) === index,\n );\n return [\n ...all.filter(({ action }) => action.destructive !== true),\n ...all.filter(({ action }) => action.destructive === true),\n ];\n}\n\n/**\n * The actions of a row (decision 0060): their icons, in their colors, with their labels as names\n * and tooltips, but the main action, which keeps its label while the row has room; and when the\n * icons don't fit, the last ones in an overflow menu, which never holds a single action. How they fit is the same for every row of the list (`RowActionsFit`), and a\n * row keeps the place of the actions of other rows that it doesn't have, so they line up.\n */\nexport function RowActions({\n itemLabel,\n actions,\n menu,\n pending,\n onRun,\n icons,\n slots,\n primary = null,\n}: RowActionsProps) {\n const intl = usePanneauIntl();\n const level = use(RowActionsFit);\n const own = orderRowActions(actions, menu);\n const all = [\n ...(slots ?? []),\n ...own.filter(({ action }) => slots?.some((slot) => slot.action.id === action.id) !== true),\n ];\n const find = (slot: ItemAction) => own.find(({ action }) => action.id === slot.action.id);\n const inMenu = level >= 2 && all.length >= 2 ? Math.min(level, all.length) : 0;\n const shown = all.slice(0, all.length - inMenu);\n const overflow = all.slice(all.length - inMenu).flatMap((slot) => find(slot) ?? []);\n const name = (action: Action) =>\n intl.formatMessage(messages.actionOnItem, {\n action: getActionLabel(action, intl),\n item: itemLabel,\n });\n const button = (entry: ItemAction) => (\n <ActionButton\n key={entry.action.id}\n action={entry.action}\n icons={icons}\n href={entry.href}\n iconOnly={level >= 1 || entry.action.id !== primary}\n isPending={pending === entry.action.id}\n isDisabled={pending !== null && pending !== entry.action.id}\n aria-label={name(entry.action)}\n onPress={() => onRun(entry.action)}\n />\n );\n // The place of an action of other rows: the same button, unseen and out of reach\n const placeholder = (key: string, content: ReactNode) => (\n <span key={key} className={styles.placeholder} aria-hidden=\"true\" inert>\n {content}\n </span>\n );\n const menuButton = (\n <IconButton\n icon={Ellipsis}\n size=\"sm\"\n appearance=\"subtle\"\n label={intl.formatMessage(messages.itemActions, { item: itemLabel })}\n showTooltip={overflow.length >= 2}\n isPending={pending !== null && overflow.some(({ action }) => action.id === pending)}\n />\n );\n return (\n <div className={styles.row} data-row-actions={all.length}>\n {shown.map((slot) => {\n const entry = find(slot);\n return entry !== undefined\n ? button(entry)\n : placeholder(slot.action.id, button({ ...slot, href: null }));\n })}\n {overflow.length >= 2 ? (\n <MenuTrigger>\n {menuButton}\n <Menu\n placement=\"bottom end\"\n onAction={(key) => {\n const entry = overflow.find(({ action }) => action.id === key);\n if (entry !== undefined && entry.href === null) {\n onRun(entry.action);\n }\n }}\n >\n {overflow.map(({ action, href }) => {\n const icon = getActionIcon(action, icons);\n return (\n <MenuItem\n key={action.id}\n id={action.id}\n isDanger={action.destructive === true}\n {...(icon !== undefined ? { icon } : {})}\n {...(href !== null ? { href } : {})}\n >\n {getActionLabel(action, intl)}\n </MenuItem>\n );\n })}\n </Menu>\n </MenuTrigger>\n ) : overflow.length === 1 && overflow[0] !== undefined ? (\n // A single action is no menu: its button, in the menu's place\n button(overflow[0])\n ) : inMenu > 0 ? (\n placeholder('menu', menuButton)\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { Action, ActionPlacement } from '@panneau/protocol';
2
- import type { ListItem } from '../types';
2
+ import type { ListItem } from '../types.js';
3
3
  /** Actions of a list: a list (grouped by their placements), or already grouped by placement. */
4
4
  export type ListActions = readonly Action[] | Partial<Record<ActionPlacement, readonly Action[]>>;
5
5
  /**
@@ -8,9 +8,10 @@ export type ListActions = readonly Action[] | Partial<Record<ActionPlacement, re
8
8
  */
9
9
  export declare function groupListActions(actions: ListActions | undefined): Record<ActionPlacement, Action[]>;
10
10
  /**
11
- * Whether an action is available on an item (decision 0011). Without abilities, the item allows
12
- * everything and the backend decides. With abilities, a link is allowed unless the item says
13
- * otherwise, and other actions only when the item lists their id.
11
+ * Whether an action is available on an item (decisions 0011 and 0040), as `isActionAllowedOn()`
12
+ * of `@panneau/core` says: the built-in item actions need their ability (`view`, `update`,
13
+ * `duplicate`, `delete`), even on an item without abilities. Other links are allowed unless the
14
+ * item says otherwise, and other actions when the item lists their id, or has no abilities.
14
15
  */
15
16
  export declare function isAllowedOn(action: Action, item: ListItem): boolean;
16
17
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/actions/actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,gGAAgG;AAChG,MAAM,MAAM,WAAW,GAAG,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;AAElG;;;GAGG;AACH,wBAAgB,gBAAgB,CAC5B,OAAO,EAAE,WAAW,GAAG,SAAS,GACjC,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC,CASnC;AAMD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAWnE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAW5E;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,CAEhF"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/actions/actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,gGAAgG;AAChG,MAAM,MAAM,WAAW,GAAG,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;AAElG;;;GAGG;AACH,wBAAgB,gBAAgB,CAC5B,OAAO,EAAE,WAAW,GAAG,SAAS,GACjC,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC,CASnC;AAMD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAEnE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAE5E;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,CAEhF"}
@@ -1,4 +1,4 @@
1
- import { canRunAction, groupActions } from "@panneau/core";
1
+ import { canRunAction, fillActionUrl, groupActions, isActionAllowedOn } from "@panneau/core";
2
2
  //#region src/actions/actions.ts
3
3
  /**
4
4
  * Groups actions by placement, without those the user can't run on the resource
@@ -24,27 +24,20 @@ function isActionList(actions) {
24
24
  return Array.isArray(actions);
25
25
  }
26
26
  /**
27
- * Whether an action is available on an item (decision 0011). Without abilities, the item allows
28
- * everything and the backend decides. With abilities, a link is allowed unless the item says
29
- * otherwise, and other actions only when the item lists their id.
27
+ * Whether an action is available on an item (decisions 0011 and 0040), as `isActionAllowedOn()`
28
+ * of `@panneau/core` says: the built-in item actions need their ability (`view`, `update`,
29
+ * `duplicate`, `delete`), even on an item without abilities. Other links are allowed unless the
30
+ * item says otherwise, and other actions when the item lists their id, or has no abilities.
30
31
  */
31
32
  function isAllowedOn(action, item) {
32
- if (!canRunAction(action)) return false;
33
- if (item.abilities === void 0) return true;
34
- if (action.kind === "link") return item.abilities[action.id] !== false;
35
- return item.abilities[action.id] === true;
33
+ return isActionAllowedOn(action, item);
36
34
  }
37
35
  /**
38
36
  * The link of a `link` action for an item: its `url` template with `{id}` (and other `{field}`
39
37
  * values of the item) filled in, or `null` for an action with a `route` or without an item.
40
38
  */
41
39
  function getActionHref(action, item) {
42
- if (action.kind !== "link" || action.url === void 0) return null;
43
- const { url } = action;
44
- return url.replace(/\{([^}]+)\}/g, (match, name) => {
45
- const value = item?.[name];
46
- return typeof value === "string" || typeof value === "number" ? encodeURIComponent(String(value)) : match;
47
- });
40
+ return fillActionUrl(action, item);
48
41
  }
49
42
  /** Whether an action's scope includes another one. */
50
43
  function hasScope(action, scope) {
@@ -1 +1 @@
1
- {"version":3,"file":"actions.js","names":[],"sources":["../../src/actions/actions.ts"],"sourcesContent":["import { canRunAction, groupActions } from '@panneau/core';\nimport type { Action, ActionPlacement } from '@panneau/protocol';\n\nimport type { ListItem } from '../types';\n\n/** Actions of a list: a list (grouped by their placements), or already grouped by placement. */\nexport type ListActions = readonly Action[] | Partial<Record<ActionPlacement, readonly Action[]>>;\n\n/**\n * Groups actions by placement, without those the user can't run on the resource\n * (`abilities.run`). Actions already grouped (as `resolveList()` does) are filtered the same way.\n */\nexport function groupListActions(\n actions: ListActions | undefined,\n): Record<ActionPlacement, Action[]> {\n if (actions === undefined) {\n return { row: [], toolbar: [], form: [], menu: [] };\n }\n if (isActionList(actions)) {\n return groupActions(actions);\n }\n const pick = (placement: ActionPlacement) => (actions[placement] ?? []).filter(canRunAction);\n return { row: pick('row'), toolbar: pick('toolbar'), form: pick('form'), menu: pick('menu') };\n}\n\nfunction isActionList(actions: ListActions): actions is readonly Action[] {\n return Array.isArray(actions);\n}\n\n/**\n * Whether an action is available on an item (decision 0011). Without abilities, the item allows\n * everything and the backend decides. With abilities, a link is allowed unless the item says\n * otherwise, and other actions only when the item lists their id.\n */\nexport function isAllowedOn(action: Action, item: ListItem): boolean {\n if (!canRunAction(action)) {\n return false;\n }\n if (item.abilities === undefined) {\n return true;\n }\n if (action.kind === 'link') {\n return item.abilities[action.id] !== false;\n }\n return item.abilities[action.id] === true;\n}\n\n/**\n * The link of a `link` action for an item: its `url` template with `{id}` (and other `{field}`\n * values of the item) filled in, or `null` for an action with a `route` or without an item.\n */\nexport function getActionHref(action: Action, item?: ListItem): string | null {\n if (action.kind !== 'link' || action.url === undefined) {\n return null;\n }\n const { url } = action;\n return url.replace(/\\{([^}]+)\\}/g, (match, name: string) => {\n const value = item?.[name];\n return typeof value === 'string' || typeof value === 'number'\n ? encodeURIComponent(String(value))\n : match;\n });\n}\n\n/** Whether an action's scope includes another one. */\nexport function hasScope(action: Action, scope: Action['scope'][number]): boolean {\n return action.scope.includes(scope);\n}\n"],"mappings":";;;;;;AAYA,SAAgB,iBACZ,SACiC;CACjC,IAAI,YAAY,KAAA,GACZ,OAAO;EAAE,KAAK,CAAA;EAAI,SAAS,CAAA;EAAI,MAAM,CAAA;EAAI,MAAM,CAAA;CAAG;CAEtD,IAAI,aAAa,OAAO,GACpB,OAAO,aAAa,OAAO;CAE/B,MAAM,QAAQ,eAAgC,QAAQ,cAAc,CAAA,EAAA,CAAI,OAAO,YAAY;CAC3F,OAAO;EAAE,KAAK,KAAK,KAAK;EAAG,SAAS,KAAK,SAAS;EAAG,MAAM,KAAK,MAAM;EAAG,MAAM,KAAK,MAAM;CAAE;AAChG;AAEA,SAAS,aAAa,SAAoD;CACtE,OAAO,MAAM,QAAQ,OAAO;AAChC;;;;;;AAOA,SAAgB,YAAY,QAAgB,MAAyB;CACjE,IAAI,CAAC,aAAa,MAAM,GACpB,OAAO;CAEX,IAAI,KAAK,cAAc,KAAA,GACnB,OAAO;CAEX,IAAI,OAAO,SAAS,QAChB,OAAO,KAAK,UAAU,OAAO,QAAQ;CAEzC,OAAO,KAAK,UAAU,OAAO,QAAQ;AACzC;;;;;AAMA,SAAgB,cAAc,QAAgB,MAAgC;CAC1E,IAAI,OAAO,SAAS,UAAU,OAAO,QAAQ,KAAA,GACzC,OAAO;CAEX,MAAM,EAAE,QAAQ;CAChB,OAAO,IAAI,QAAQ,iBAAiB,OAAO,SAAiB;EACxD,MAAM,QAAQ,OAAO;EACrB,OAAO,OAAO,UAAU,YAAY,OAAO,UAAU,WAC/C,mBAAmB,OAAO,KAAK,CAAC,IAChC;CACV,CAAC;AACL;;AAGA,SAAgB,SAAS,QAAgB,OAAyC;CAC9E,OAAO,OAAO,MAAM,SAAS,KAAK;AACtC"}
1
+ {"version":3,"file":"actions.js","names":["canRunAction","fillActionUrl","groupActions","isActionAllowedOn","Action","ActionPlacement","ListItem","ListActions","Partial","Record","groupListActions","actions","undefined","row","toolbar","form","menu","isActionList","pick","placement","filter","Array","isArray","isAllowedOn","action","item","getActionHref","hasScope","scope","includes"],"sources":["../../src/actions/actions.ts"],"sourcesContent":["import { canRunAction, fillActionUrl, groupActions, isActionAllowedOn } from '@panneau/core';\nimport type { Action, ActionPlacement } from '@panneau/protocol';\n\nimport type { ListItem } from '../types';\n\n/** Actions of a list: a list (grouped by their placements), or already grouped by placement. */\nexport type ListActions = readonly Action[] | Partial<Record<ActionPlacement, readonly Action[]>>;\n\n/**\n * Groups actions by placement, without those the user can't run on the resource\n * (`abilities.run`). Actions already grouped (as `resolveList()` does) are filtered the same way.\n */\nexport function groupListActions(\n actions: ListActions | undefined,\n): Record<ActionPlacement, Action[]> {\n if (actions === undefined) {\n return { row: [], toolbar: [], form: [], menu: [] };\n }\n if (isActionList(actions)) {\n return groupActions(actions);\n }\n const pick = (placement: ActionPlacement) => (actions[placement] ?? []).filter(canRunAction);\n return { row: pick('row'), toolbar: pick('toolbar'), form: pick('form'), menu: pick('menu') };\n}\n\nfunction isActionList(actions: ListActions): actions is readonly Action[] {\n return Array.isArray(actions);\n}\n\n/**\n * Whether an action is available on an item (decisions 0011 and 0040), as `isActionAllowedOn()`\n * of `@panneau/core` says: the built-in item actions need their ability (`view`, `update`,\n * `duplicate`, `delete`), even on an item without abilities. Other links are allowed unless the\n * item says otherwise, and other actions when the item lists their id, or has no abilities.\n */\nexport function isAllowedOn(action: Action, item: ListItem): boolean {\n return isActionAllowedOn(action, item);\n}\n\n/**\n * The link of a `link` action for an item: its `url` template with `{id}` (and other `{field}`\n * values of the item) filled in, or `null` for an action with a `route` or without an item.\n */\nexport function getActionHref(action: Action, item?: ListItem): string | null {\n return fillActionUrl(action, item);\n}\n\n/** Whether an action's scope includes another one. */\nexport function hasScope(action: Action, scope: Action['scope'][number]): boolean {\n return action.scope.includes(scope);\n}\n"],"mappings":";;;;;;AAYA,SAAgBU,iBACZC,SACiC;CACjC,IAAIA,YAAYC,KAAAA,GACZ,OAAO;EAAEC,KAAK,CAAA;EAAIC,SAAS,CAAA;EAAIC,MAAM,CAAA;EAAIC,MAAM,CAAA;CAAG;CAEtD,IAAIC,aAAaN,OAAO,GACpB,OAAOT,aAAaS,OAAO;CAE/B,MAAMO,QAAQC,eAAgCR,QAAQQ,cAAc,CAAA,EAAA,CAAIC,OAAOpB,YAAY;CAC3F,OAAO;EAAEa,KAAKK,KAAK,KAAK;EAAGJ,SAASI,KAAK,SAAS;EAAGH,MAAMG,KAAK,MAAM;EAAGF,MAAME,KAAK,MAAM;CAAE;AAChG;AAEA,SAASD,aAAaN,SAAoD;CACtE,OAAOU,MAAMC,QAAQX,OAAO;AAChC;;;;;;;AAQA,SAAgBY,YAAYC,QAAgBC,MAAyB;CACjE,OAAOtB,kBAAkBqB,QAAQC,IAAI;AACzC;;;;;AAMA,SAAgBC,cAAcF,QAAgBC,MAAgC;CAC1E,OAAOxB,cAAcuB,QAAQC,IAAI;AACrC;;AAGA,SAAgBE,SAASH,QAAgBI,OAAyC;CAC9E,OAAOJ,OAAOI,MAAMC,SAASD,KAAK;AACtC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * How the actions of rows fit (decision 0060), the same for every row of a list: `0`, every
3
+ * action as an icon but the main one, with its label; `1`, every action as an icon; `n` from 2,
4
+ * the last `n` actions of each row in its menu.
5
+ */
6
+ export declare const RowActionsFit: import("react").Context<number>;
7
+ /** What the fit of a list depends on, besides its width: its items and its columns. */
8
+ export declare function fitContent(items: readonly {
9
+ id: string;
10
+ }[], columns: readonly {
11
+ id: string;
12
+ }[]): string;
13
+ /**
14
+ * Fits the actions of the rows of a list in the room they have (decision 0060). It draws each
15
+ * level in turn, from every action as an icon but the main one, labelled, then the main one as an
16
+ * icon too, then a menu of two actions, three…, while the next one may help, and keeps the best:
17
+ * where the actions crowd least (the list overflows, the actions of a row wrap or take more than
18
+ * 40% of it), then, on rows of five actions or more, where the rows are shortest (their content
19
+ * wraps or is cut less), then the fewest actions in the menu.
20
+ *
21
+ * @returns the level, and a callback ref for the element to measure: the list, which holds the
22
+ * actions.
23
+ */
24
+ export declare function useRowActionsFit(content: string): [level: number, measure: (element: HTMLElement | null) => void];
25
+ //# sourceMappingURL=fit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fit.d.ts","sourceRoot":"","sources":["../../src/actions/fit.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,aAAa,iCAAmB,CAAC;AAE9C,uFAAuF;AACvF,wBAAgB,UAAU,CACtB,KAAK,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,EAChC,OAAO,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,GACnC,MAAM,CAER;AAgKD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC5B,OAAO,EAAE,MAAM,GAChB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC,CA8BjE"}
@@ -0,0 +1,197 @@
1
+ import { c } from "react/compiler-runtime";
2
+ import { createContext, useEffect, useLayoutEffect, useState, useSyncExternalStore } from "react";
3
+ //#region src/actions/fit.ts
4
+ /**
5
+ * How the actions of rows fit (decision 0060), the same for every row of a list: `0`, every
6
+ * action as an icon but the main one, with its label; `1`, every action as an icon; `n` from 2,
7
+ * the last `n` actions of each row in its menu.
8
+ */
9
+ var RowActionsFit = createContext(0);
10
+ /** What the fit of a list depends on, besides its width: its items and its columns. */
11
+ function fitContent(items, columns) {
12
+ return `${items.map((item) => item.id).join("\0")}\u0001${columns.map((column) => column.id).join("\0")}`;
13
+ }
14
+ /** Past that many actions in the menu, a row has nothing left to free. */
15
+ var MAX_LEVEL = 12;
16
+ /** The most of the width of its row that the actions of an item take before they crowd it. */
17
+ var SHARE = .4;
18
+ /**
19
+ * From that many actions on a row, they also go to the menu to give the content room, as long as
20
+ * `SHOWN` of them stay out of it.
21
+ */
22
+ var MANY = 5;
23
+ var SHOWN = 4;
24
+ function measure(element) {
25
+ let crowding = Math.max(0, element.scrollWidth - element.clientWidth);
26
+ let count = 0;
27
+ for (const actions of element.querySelectorAll("[data-row-actions]")) {
28
+ count = Math.max(count, Number(actions.dataset.rowActions));
29
+ const box = actions.parentElement;
30
+ if (box !== null) crowding += Math.max(0, box.scrollWidth - box.clientWidth);
31
+ const first = actions.firstElementChild;
32
+ if (first instanceof HTMLElement) crowding += Math.max(0, actions.offsetHeight - first.offsetHeight);
33
+ const row = actions.closest("tr, li") ?? element;
34
+ crowding += Math.max(0, actions.offsetWidth - row.offsetWidth * SHARE);
35
+ }
36
+ let cut = 0;
37
+ for (const text of element.querySelectorAll("[data-clamp]")) cut += Math.max(0, text.scrollHeight - text.clientHeight);
38
+ return {
39
+ height: element.offsetHeight + cut,
40
+ crowding,
41
+ count
42
+ };
43
+ }
44
+ /**
45
+ * Whether rows of `count` actions can give the content room with `level`: only when they have many
46
+ * actions, `SHOWN` of which stay out of the menu.
47
+ */
48
+ function forContent(level, count) {
49
+ return count >= MANY && count - level >= SHOWN;
50
+ }
51
+ /** Whether the next level is worth a try, after `current`. */
52
+ function worthTrying(next, current) {
53
+ if (next === 1) return current.crowding > .5 || forContent(next, current.count);
54
+ return next <= Math.min(current.count, MAX_LEVEL) && current.count >= 2 && (current.crowding > .5 || forContent(next, current.count));
55
+ }
56
+ /**
57
+ * The best of the levels tried: the actions crowd least, then the rows are shortest (when the
58
+ * level may give the content room), then the fewest changes.
59
+ */
60
+ function best(measures) {
61
+ let chosen = 0;
62
+ for (const [level, current] of measures) {
63
+ const kept = measures.get(chosen);
64
+ if (kept === void 0 || level === chosen) continue;
65
+ if (current.crowding < kept.crowding - .5) chosen = level;
66
+ else if (current.crowding <= kept.crowding + .5 && forContent(level, current.count) && current.height < kept.height - .5) chosen = level;
67
+ }
68
+ return chosen;
69
+ }
70
+ /**
71
+ * The level of a list, outside React: it changes while the list commits, and React draws each
72
+ * change at once (`useSyncExternalStore`), before the browser paints.
73
+ */
74
+ var FitStore = class {
75
+ #level = 0;
76
+ #settled = false;
77
+ /** The measures of the levels tried. */
78
+ #measures = /* @__PURE__ */ new Map();
79
+ #content = null;
80
+ #listeners = /* @__PURE__ */ new Set();
81
+ subscribe = (listener) => {
82
+ this.#listeners.add(listener);
83
+ return () => this.#listeners.delete(listener);
84
+ };
85
+ getLevel = () => this.#level;
86
+ #set(level) {
87
+ if (level !== this.#level) {
88
+ this.#level = level;
89
+ for (const listener of this.#listeners) listener();
90
+ }
91
+ }
92
+ /** Starts over from the labels: true when the list has to draw them first. */
93
+ restart() {
94
+ this.#settled = false;
95
+ this.#measures = /* @__PURE__ */ new Map();
96
+ const drawn = this.#level === 0;
97
+ this.#set(0);
98
+ return !drawn;
99
+ }
100
+ /** Starts over when the content changes. */
101
+ setContent(content) {
102
+ if (content === this.#content) return false;
103
+ this.#content = content;
104
+ return this.restart();
105
+ }
106
+ /** Measures the list drawn at `drawn`, then tries the next level, or settles on the best. */
107
+ step(element, drawn) {
108
+ if (this.#settled || drawn !== this.#level) return;
109
+ const current = measure(element);
110
+ this.#measures.set(drawn, current);
111
+ const next = drawn + 1;
112
+ if (worthTrying(next, current)) this.#set(next);
113
+ else {
114
+ this.#settled = true;
115
+ this.#set(best(this.#measures));
116
+ }
117
+ }
118
+ };
119
+ /**
120
+ * Fits the actions of the rows of a list in the room they have (decision 0060). It draws each
121
+ * level in turn, from every action as an icon but the main one, labelled, then the main one as an
122
+ * icon too, then a menu of two actions, three…, while the next one may help, and keeps the best:
123
+ * where the actions crowd least (the list overflows, the actions of a row wrap or take more than
124
+ * 40% of it), then, on rows of five actions or more, where the rows are shortest (their content
125
+ * wraps or is cut less), then the fewest actions in the menu.
126
+ *
127
+ * @returns the level, and a callback ref for the element to measure: the list, which holds the
128
+ * actions.
129
+ */
130
+ function useRowActionsFit(content) {
131
+ const $ = c(12);
132
+ const [element, setElement] = useState(null);
133
+ const [store] = useState(_temp);
134
+ const level = useSyncExternalStore(store.subscribe, store.getLevel, store.getLevel);
135
+ let t0;
136
+ let t1;
137
+ if ($[0] !== content || $[1] !== element || $[2] !== level || $[3] !== store) {
138
+ t0 = () => {
139
+ if (element !== null && !store.setContent(content)) store.step(element, level);
140
+ };
141
+ t1 = [
142
+ store,
143
+ element,
144
+ content,
145
+ level
146
+ ];
147
+ $[0] = content;
148
+ $[1] = element;
149
+ $[2] = level;
150
+ $[3] = store;
151
+ $[4] = t0;
152
+ $[5] = t1;
153
+ } else {
154
+ t0 = $[4];
155
+ t1 = $[5];
156
+ }
157
+ useLayoutEffect(t0, t1);
158
+ let t2;
159
+ let t3;
160
+ if ($[6] !== element || $[7] !== store) {
161
+ t2 = () => {
162
+ if (element === null || typeof ResizeObserver === "undefined") return;
163
+ let width = element.clientWidth;
164
+ const observer = new ResizeObserver(() => {
165
+ if (element.clientWidth !== width) {
166
+ width = element.clientWidth;
167
+ if (!store.restart()) store.step(element, 0);
168
+ }
169
+ });
170
+ observer.observe(element);
171
+ return () => observer.disconnect();
172
+ };
173
+ t3 = [store, element];
174
+ $[6] = element;
175
+ $[7] = store;
176
+ $[8] = t2;
177
+ $[9] = t3;
178
+ } else {
179
+ t2 = $[8];
180
+ t3 = $[9];
181
+ }
182
+ useEffect(t2, t3);
183
+ let t4;
184
+ if ($[10] !== level) {
185
+ t4 = [level, setElement];
186
+ $[10] = level;
187
+ $[11] = t4;
188
+ } else t4 = $[11];
189
+ return t4;
190
+ }
191
+ function _temp() {
192
+ return new FitStore();
193
+ }
194
+ //#endregion
195
+ export { RowActionsFit, fitContent, useRowActionsFit };
196
+
197
+ //# sourceMappingURL=fit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fit.js","names":["createContext","useEffect","useLayoutEffect","useState","useSyncExternalStore","RowActionsFit","fitContent","items","id","columns","map","item","join","column","MAX_LEVEL","SHARE","MANY","SHOWN","Measure","height","crowding","count","measure","element","HTMLElement","Math","max","scrollWidth","clientWidth","actions","querySelectorAll","Number","dataset","rowActions","box","parentElement","first","firstElementChild","offsetHeight","row","closest","offsetWidth","cut","text","scrollHeight","clientHeight","forContent","level","worthTrying","next","current","min","best","measures","ReadonlyMap","chosen","kept","get","undefined","FitStore","settled","Map","content","listeners","Set","subscribe","listener","add","delete","getLevel","set","#set","restart","drawn","setContent","step","useRowActionsFit","$","_c","setElement","store","_temp","t0","t1","t2","t3","ResizeObserver","width","observer","observe","disconnect","t4","_c"],"sources":["../../src/actions/fit.ts"],"sourcesContent":["import { createContext, useEffect, useLayoutEffect, useState, useSyncExternalStore } from 'react';\n\n/**\n * How the actions of rows fit (decision 0060), the same for every row of a list: `0`, every\n * action as an icon but the main one, with its label; `1`, every action as an icon; `n` from 2,\n * the last `n` actions of each row in its menu.\n */\nexport const RowActionsFit = createContext(0);\n\n/** What the fit of a list depends on, besides its width: its items and its columns. */\nexport function fitContent(\n items: readonly { id: string }[],\n columns: readonly { id: string }[],\n): string {\n return `${items.map((item) => item.id).join('\\u0000')}\\u0001${columns.map((column) => column.id).join('\\u0000')}`;\n}\n\n/** Past that many actions in the menu, a row has nothing left to free. */\nconst MAX_LEVEL = 12;\n\n/** The most of the width of its row that the actions of an item take before they crowd it. */\nconst SHARE = 0.4;\n\n/**\n * From that many actions on a row, they also go to the menu to give the content room, as long as\n * `SHOWN` of them stay out of it.\n */\nconst MANY = 5;\nconst SHOWN = 4;\n\ninterface Measure {\n /**\n * The room the content lacks: the height of the list, since rows grow when their content\n * wraps, and what the displays that clamp their text (`data-clamp`) cut off.\n */\n height: number;\n /**\n * How much the actions don't fit, in pixels: what the list and the boxes of actions overflow,\n * the lines that actions wrap to, and what they take of their row past `SHARE`.\n */\n crowding: number;\n /** The most actions a row has, in the row and its menu. */\n count: number;\n}\n\nfunction measure(element: HTMLElement): Measure {\n let crowding = Math.max(0, element.scrollWidth - element.clientWidth);\n let count = 0;\n for (const actions of element.querySelectorAll<HTMLElement>('[data-row-actions]')) {\n count = Math.max(count, Number(actions.dataset.rowActions));\n const box = actions.parentElement;\n if (box !== null) {\n crowding += Math.max(0, box.scrollWidth - box.clientWidth);\n }\n const first = actions.firstElementChild;\n if (first instanceof HTMLElement) {\n crowding += Math.max(0, actions.offsetHeight - first.offsetHeight);\n }\n const row = actions.closest<HTMLElement>('tr, li') ?? element;\n crowding += Math.max(0, actions.offsetWidth - row.offsetWidth * SHARE);\n }\n let cut = 0;\n for (const text of element.querySelectorAll<HTMLElement>('[data-clamp]')) {\n cut += Math.max(0, text.scrollHeight - text.clientHeight);\n }\n return { height: element.offsetHeight + cut, crowding, count };\n}\n\n/**\n * Whether rows of `count` actions can give the content room with `level`: only when they have many\n * actions, `SHOWN` of which stay out of the menu.\n */\nfunction forContent(level: number, count: number): boolean {\n return count >= MANY && count - level >= SHOWN;\n}\n\n/** Whether the next level is worth a try, after `current`. */\nfunction worthTrying(next: number, current: Measure): boolean {\n if (next === 1) {\n return current.crowding > 0.5 || forContent(next, current.count);\n }\n return (\n next <= Math.min(current.count, MAX_LEVEL) &&\n current.count >= 2 &&\n (current.crowding > 0.5 || forContent(next, current.count))\n );\n}\n\n/**\n * The best of the levels tried: the actions crowd least, then the rows are shortest (when the\n * level may give the content room), then the fewest changes.\n */\nfunction best(measures: ReadonlyMap<number, Measure>): number {\n let chosen = 0;\n for (const [level, current] of measures) {\n const kept = measures.get(chosen);\n if (kept === undefined || level === chosen) {\n continue;\n }\n if (current.crowding < kept.crowding - 0.5) {\n chosen = level;\n } else if (\n current.crowding <= kept.crowding + 0.5 &&\n forContent(level, current.count) &&\n current.height < kept.height - 0.5\n ) {\n chosen = level;\n }\n }\n return chosen;\n}\n\n/**\n * The level of a list, outside React: it changes while the list commits, and React draws each\n * change at once (`useSyncExternalStore`), before the browser paints.\n */\nclass FitStore {\n #level = 0;\n #settled = false;\n /** The measures of the levels tried. */\n #measures = new Map<number, Measure>();\n #content: string | null = null;\n readonly #listeners = new Set<() => void>();\n\n readonly subscribe = (listener: () => void): (() => void) => {\n this.#listeners.add(listener);\n return () => this.#listeners.delete(listener);\n };\n\n readonly getLevel = (): number => this.#level;\n\n #set(level: number): void {\n if (level !== this.#level) {\n this.#level = level;\n for (const listener of this.#listeners) {\n listener();\n }\n }\n }\n\n /** Starts over from the labels: true when the list has to draw them first. */\n restart(): boolean {\n this.#settled = false;\n this.#measures = new Map();\n const drawn = this.#level === 0;\n this.#set(0);\n return !drawn;\n }\n\n /** Starts over when the content changes. */\n setContent(content: string): boolean {\n if (content === this.#content) {\n return false;\n }\n this.#content = content;\n return this.restart();\n }\n\n /** Measures the list drawn at `drawn`, then tries the next level, or settles on the best. */\n step(element: HTMLElement, drawn: number): void {\n if (this.#settled || drawn !== this.#level) {\n return;\n }\n const current = measure(element);\n this.#measures.set(drawn, current);\n const next = drawn + 1;\n if (worthTrying(next, current)) {\n this.#set(next);\n } else {\n this.#settled = true;\n this.#set(best(this.#measures));\n }\n }\n}\n\n/**\n * Fits the actions of the rows of a list in the room they have (decision 0060). It draws each\n * level in turn, from every action as an icon but the main one, labelled, then the main one as an\n * icon too, then a menu of two actions, three…, while the next one may help, and keeps the best:\n * where the actions crowd least (the list overflows, the actions of a row wrap or take more than\n * 40% of it), then, on rows of five actions or more, where the rows are shortest (their content\n * wraps or is cut less), then the fewest actions in the menu.\n *\n * @returns the level, and a callback ref for the element to measure: the list, which holds the\n * actions.\n */\nexport function useRowActionsFit(\n content: string,\n): [level: number, measure: (element: HTMLElement | null) => void] {\n const [element, setElement] = useState<HTMLElement | null>(null);\n const [store] = useState(() => new FitStore());\n const level = useSyncExternalStore(store.subscribe, store.getLevel, store.getLevel);\n\n useLayoutEffect(() => {\n if (element !== null && !store.setContent(content)) {\n store.step(element, level);\n }\n }, [store, element, content, level]);\n\n useEffect(() => {\n // Without ResizeObserver (jsdom), the list fits once, at its first width.\n if (element === null || typeof ResizeObserver === 'undefined') {\n return undefined;\n }\n let width = element.clientWidth;\n const observer = new ResizeObserver(() => {\n if (element.clientWidth !== width) {\n width = element.clientWidth;\n if (!store.restart()) {\n store.step(element, 0);\n }\n }\n });\n observer.observe(element);\n return () => observer.disconnect();\n }, [store, element]);\n\n return [level, setElement];\n}\n"],"mappings":"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"}
@@ -7,4 +7,9 @@ export type ActionIcons = Readonly<Record<string, IconComponent>>;
7
7
  * names (`"send"`, loaded when it first renders), then the icon of a built-in action.
8
8
  */
9
9
  export declare function getActionIcon(action: Action, icons?: ActionIcons): IconComponent | undefined;
10
+ /**
11
+ * The tone of an action in rows (decision 0060): `danger` when it destroys, a color for `show`
12
+ * (`info`), `edit` (`accent`) and `restore` (`success`), and `neutral` for the others.
13
+ */
14
+ export declare function getActionTone(action: Action): 'neutral' | 'accent' | 'info' | 'success' | 'danger';
10
15
  //# sourceMappingURL=icons.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/actions/icons.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,KAAK,aAAa,EAAgB,MAAM,aAAa,CAAC;AAE/D,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;AAalE;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,SAAS,CAU5F"}
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/actions/icons.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,KAAK,aAAa,EAAgB,MAAM,aAAa,CAAC;AAE/D,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;AAalE;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,SAAS,CAU5F;AASD;;;GAGG;AACH,wBAAgB,aAAa,CACzB,MAAM,EAAE,MAAM,GACf,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAOtD"}
@@ -21,7 +21,21 @@ function getActionIcon(action, icons) {
21
21
  if (action.icon !== void 0 && action.icon !== "") return getNamedIcon(action.icon);
22
22
  return Object.hasOwn(BUILT_IN_ICONS, action.id) ? BUILT_IN_ICONS[action.id] : void 0;
23
23
  }
24
+ /** Colors of the built-in actions in rows, as Panneau 4 had them (decision 0060). */
25
+ var BUILT_IN_TONES = {
26
+ show: "info",
27
+ edit: "accent",
28
+ restore: "success"
29
+ };
30
+ /**
31
+ * The tone of an action in rows (decision 0060): `danger` when it destroys, a color for `show`
32
+ * (`info`), `edit` (`accent`) and `restore` (`success`), and `neutral` for the others.
33
+ */
34
+ function getActionTone(action) {
35
+ if (action.destructive === true) return "danger";
36
+ return Object.hasOwn(BUILT_IN_TONES, action.id) ? BUILT_IN_TONES[action.id] ?? "neutral" : "neutral";
37
+ }
24
38
  //#endregion
25
- export { getActionIcon };
39
+ export { getActionIcon, getActionTone };
26
40
 
27
41
  //# sourceMappingURL=icons.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"icons.js","names":[],"sources":["../../src/actions/icons.ts"],"sourcesContent":["import {\n Copy,\n Download,\n Eye,\n type LucideIcon,\n Pencil,\n RotateCcw,\n Trash2,\n Upload,\n} from 'lucide-react';\n\nimport type { Action } from '@panneau/protocol';\nimport { type IconComponent, getNamedIcon } from '@panneau/ui';\n\n/** Icons of actions by action id, for actions written in code (`{ archive: Archive }`). */\nexport type ActionIcons = Readonly<Record<string, IconComponent>>;\n\n/** Icons of the built-in actions, when they don't name one. */\nconst BUILT_IN_ICONS: Record<string, LucideIcon> = {\n show: Eye,\n edit: Pencil,\n duplicate: Copy,\n delete: Trash2,\n restore: RotateCcw,\n export: Download,\n import: Upload,\n};\n\n/**\n * The icon of an action: the one given for its id in `icons`, then the Lucide icon its `icon`\n * names (`\"send\"`, loaded when it first renders), then the icon of a built-in action.\n */\nexport function getActionIcon(action: Action, icons?: ActionIcons): IconComponent | undefined {\n const given =\n icons !== undefined && Object.hasOwn(icons, action.id) ? icons[action.id] : undefined;\n if (given !== undefined) {\n return given;\n }\n if (action.icon !== undefined && action.icon !== '') {\n return getNamedIcon(action.icon);\n }\n return Object.hasOwn(BUILT_IN_ICONS, action.id) ? BUILT_IN_ICONS[action.id] : undefined;\n}\n"],"mappings":";;;;AAkBA,IAAM,iBAA6C;CAC/C,MAAM;CACN,MAAM;CACN,WAAW;CACX,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;AACZ;;;;;AAMA,SAAgB,cAAc,QAAgB,OAAgD;CAC1F,MAAM,QACF,UAAU,KAAA,KAAa,OAAO,OAAO,OAAO,OAAO,EAAE,IAAI,MAAM,OAAO,MAAM,KAAA;CAChF,IAAI,UAAU,KAAA,GACV,OAAO;CAEX,IAAI,OAAO,SAAS,KAAA,KAAa,OAAO,SAAS,IAC7C,OAAO,aAAa,OAAO,IAAI;CAEnC,OAAO,OAAO,OAAO,gBAAgB,OAAO,EAAE,IAAI,eAAe,OAAO,MAAM,KAAA;AAClF"}
1
+ {"version":3,"file":"icons.js","names":["Copy","Download","Eye","LucideIcon","Pencil","RotateCcw","Trash2","Upload","Action","IconComponent","getNamedIcon","ActionIcons","Readonly","Record","BUILT_IN_ICONS","show","edit","duplicate","delete","restore","export","import","getActionIcon","action","icons","given","undefined","Object","hasOwn","id","icon","BUILT_IN_TONES","getActionTone","destructive"],"sources":["../../src/actions/icons.ts"],"sourcesContent":["import {\n Copy,\n Download,\n Eye,\n type LucideIcon,\n Pencil,\n RotateCcw,\n Trash2,\n Upload,\n} from 'lucide-react';\n\nimport type { Action } from '@panneau/protocol';\nimport { type IconComponent, getNamedIcon } from '@panneau/ui';\n\n/** Icons of actions by action id, for actions written in code (`{ archive: Archive }`). */\nexport type ActionIcons = Readonly<Record<string, IconComponent>>;\n\n/** Icons of the built-in actions, when they don't name one. */\nconst BUILT_IN_ICONS: Record<string, LucideIcon> = {\n show: Eye,\n edit: Pencil,\n duplicate: Copy,\n delete: Trash2,\n restore: RotateCcw,\n export: Download,\n import: Upload,\n};\n\n/**\n * The icon of an action: the one given for its id in `icons`, then the Lucide icon its `icon`\n * names (`\"send\"`, loaded when it first renders), then the icon of a built-in action.\n */\nexport function getActionIcon(action: Action, icons?: ActionIcons): IconComponent | undefined {\n const given =\n icons !== undefined && Object.hasOwn(icons, action.id) ? icons[action.id] : undefined;\n if (given !== undefined) {\n return given;\n }\n if (action.icon !== undefined && action.icon !== '') {\n return getNamedIcon(action.icon);\n }\n return Object.hasOwn(BUILT_IN_ICONS, action.id) ? BUILT_IN_ICONS[action.id] : undefined;\n}\n\n/** Colors of the built-in actions in rows, as Panneau 4 had them (decision 0060). */\nconst BUILT_IN_TONES: Record<string, 'accent' | 'info' | 'success'> = {\n show: 'info',\n edit: 'accent',\n restore: 'success',\n};\n\n/**\n * The tone of an action in rows (decision 0060): `danger` when it destroys, a color for `show`\n * (`info`), `edit` (`accent`) and `restore` (`success`), and `neutral` for the others.\n */\nexport function getActionTone(\n action: Action,\n): 'neutral' | 'accent' | 'info' | 'success' | 'danger' {\n if (action.destructive === true) {\n return 'danger';\n }\n return Object.hasOwn(BUILT_IN_TONES, action.id)\n ? (BUILT_IN_TONES[action.id] ?? 'neutral')\n : 'neutral';\n}\n"],"mappings":";;;;AAkBA,IAAMc,iBAA6C;CAC/CC,MAAMb;CACNc,MAAMZ;CACNa,WAAWjB;CACXkB,QAAQZ;CACRa,SAASd;CACTe,QAAQnB;CACRoB,QAAQd;AACZ;;;;;AAMA,SAAgBe,cAAcC,QAAgBC,OAAgD;CAC1F,MAAMC,QACFD,UAAUE,KAAAA,KAAaC,OAAOC,OAAOJ,OAAOD,OAAOM,EAAE,IAAIL,MAAMD,OAAOM,MAAMH,KAAAA;CAChF,IAAID,UAAUC,KAAAA,GACV,OAAOD;CAEX,IAAIF,OAAOO,SAASJ,KAAAA,KAAaH,OAAOO,SAAS,IAC7C,OAAOpB,aAAaa,OAAOO,IAAI;CAEnC,OAAOH,OAAOC,OAAOd,gBAAgBS,OAAOM,EAAE,IAAIf,eAAeS,OAAOM,MAAMH,KAAAA;AAClF;;AAGA,IAAMK,iBAAgE;CAClEhB,MAAM;CACNC,MAAM;CACNG,SAAS;AACb;;;;;AAMA,SAAgBa,cACZT,QACoD;CACpD,IAAIA,OAAOU,gBAAgB,MACvB,OAAO;CAEX,OAAON,OAAOC,OAAOG,gBAAgBR,OAAOM,EAAE,IACvCE,eAAeR,OAAOM,OAAO,YAC9B;AACV"}
@@ -0,0 +1,10 @@
1
+ import type { ListColumn } from './types.js';
2
+ /** The columns shown by default: those that aren't hidden (decision 0042). */
3
+ export declare function getDefaultColumns<T extends ListColumn>(columns: readonly T[]): T[];
4
+ /**
5
+ * The columns shown, in their order: those of `ids` (the view of the list), or the defaults
6
+ * without it. Ids of columns that don't exist are ignored, and columns that can't be hidden are
7
+ * added where the definition has them.
8
+ */
9
+ export declare function getShownColumns<T extends ListColumn>(columns: readonly T[], ids: readonly string[] | undefined): T[];
10
+ //# sourceMappingURL=columns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"columns.d.ts","sourceRoot":"","sources":["../src/columns.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAM1C,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,UAAU,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,CAElF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,UAAU,EAChD,OAAO,EAAE,SAAS,CAAC,EAAE,EACrB,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GACnC,CAAC,EAAE,CAcL"}
@@ -0,0 +1,25 @@
1
+ //#region src/columns.ts
2
+ function isHideable(column) {
3
+ return column.hideable !== false;
4
+ }
5
+ /** The columns shown by default: those that aren't hidden (decision 0042). */
6
+ function getDefaultColumns(columns) {
7
+ return columns.filter((column) => column.hidden !== true || !isHideable(column));
8
+ }
9
+ /**
10
+ * The columns shown, in their order: those of `ids` (the view of the list), or the defaults
11
+ * without it. Ids of columns that don't exist are ignored, and columns that can't be hidden are
12
+ * added where the definition has them.
13
+ */
14
+ function getShownColumns(columns, ids) {
15
+ if (ids === void 0) return getDefaultColumns(columns);
16
+ const shown = ids.filter((id, index) => ids.indexOf(id) === index).map((id) => columns.find((column) => column.id === id)).filter((column) => column !== void 0);
17
+ columns.forEach((column, index) => {
18
+ if (!isHideable(column) && !shown.includes(column)) shown.splice(Math.min(index, shown.length), 0, column);
19
+ });
20
+ return shown.length > 0 ? shown : getDefaultColumns(columns);
21
+ }
22
+ //#endregion
23
+ export { getDefaultColumns, getShownColumns };
24
+
25
+ //# sourceMappingURL=columns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"columns.js","names":["ListColumn","isHideable","column","hideable","getDefaultColumns","columns","T","filter","hidden","getShownColumns","ids","undefined","shown","id","index","indexOf","map","find","forEach","includes","splice","Math","min","length"],"sources":["../src/columns.ts"],"sourcesContent":["import type { ListColumn } from './types';\n\nfunction isHideable(column: ListColumn): boolean {\n return column.hideable !== false;\n}\n\n/** The columns shown by default: those that aren't hidden (decision 0042). */\nexport function getDefaultColumns<T extends ListColumn>(columns: readonly T[]): T[] {\n return columns.filter((column) => column.hidden !== true || !isHideable(column));\n}\n\n/**\n * The columns shown, in their order: those of `ids` (the view of the list), or the defaults\n * without it. Ids of columns that don't exist are ignored, and columns that can't be hidden are\n * added where the definition has them.\n */\nexport function getShownColumns<T extends ListColumn>(\n columns: readonly T[],\n ids: readonly string[] | undefined,\n): T[] {\n if (ids === undefined) {\n return getDefaultColumns(columns);\n }\n const shown = ids\n .filter((id, index) => ids.indexOf(id) === index)\n .map((id) => columns.find((column) => column.id === id))\n .filter((column): column is T => column !== undefined);\n columns.forEach((column, index) => {\n if (!isHideable(column) && !shown.includes(column)) {\n shown.splice(Math.min(index, shown.length), 0, column);\n }\n });\n return shown.length > 0 ? shown : getDefaultColumns(columns);\n}\n"],"mappings":";AAEA,SAASC,WAAWC,QAA6B;CAC7C,OAAOA,OAAOC,aAAa;AAC/B;;AAGA,SAAgBC,kBAAwCC,SAA4B;CAChF,OAAOA,QAAQE,QAAQL,WAAWA,OAAOM,WAAW,QAAQ,CAACP,WAAWC,MAAM,CAAC;AACnF;;;;;;AAOA,SAAgBO,gBACZJ,SACAK,KACG;CACH,IAAIA,QAAQC,KAAAA,GACR,OAAOP,kBAAkBC,OAAO;CAEpC,MAAMO,QAAQF,IACTH,QAAQM,IAAIC,UAAUJ,IAAIK,QAAQF,EAAE,MAAMC,KAAK,CAAC,CAChDE,KAAKH,OAAOR,QAAQY,MAAMf,WAAWA,OAAOW,OAAOA,EAAE,CAAC,CAAC,CACvDN,QAAQL,WAAwBA,WAAWS,KAAAA,CAAS;CACzDN,QAAQa,SAAShB,QAAQY,UAAU;EAC/B,IAAI,CAACb,WAAWC,MAAM,KAAK,CAACU,MAAMO,SAASjB,MAAM,GAC7CU,MAAMQ,OAAOC,KAAKC,IAAIR,OAAOF,MAAMW,MAAM,GAAG,GAAGrB,MAAM;CAE7D,CAAC;CACD,OAAOU,MAAMW,SAAS,IAAIX,QAAQR,kBAAkBC,OAAO;AAC/D"}
package/dist/cx.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cx.js","names":[],"sources":["../src/cx.ts"],"sourcesContent":["/** Joins class names, skipping empty ones. */\nexport function cx(...classNames: (string | false | null | undefined)[]): string {\n return classNames.filter(Boolean).join(' ');\n}\n"],"mappings":";;AACA,SAAgB,GAAG,GAAG,YAA2D;CAC7E,OAAO,WAAW,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;AAC9C"}
1
+ {"version":3,"file":"cx.js","names":["cx","classNames","filter","Boolean","join"],"sources":["../src/cx.ts"],"sourcesContent":["/** Joins class names, skipping empty ones. */\nexport function cx(...classNames: (string | false | null | undefined)[]): string {\n return classNames.filter(Boolean).join(' ');\n}\n"],"mappings":";;AACA,SAAgBA,GAAG,GAAGC,YAA2D;CAC7E,OAAOA,WAAWC,OAAOC,OAAO,CAAC,CAACC,KAAK,GAAG;AAC9C"}
@@ -47,6 +47,12 @@
47
47
  font-size: var(--panneau-font-size-sm);
48
48
  }
49
49
 
50
+ .panneau-displays-palette-color {
51
+ display: inline-flex;
52
+ align-items: center;
53
+ gap: var(--panneau-space-2);
54
+ }
55
+
50
56
  .panneau-displays-swatch {
51
57
  flex: none;
52
58
  width: 1rem;
@@ -61,6 +67,12 @@
61
67
  gap: var(--panneau-space-2);
62
68
  }
63
69
 
70
+ .panneau-displays-files {
71
+ display: inline-flex;
72
+ flex-direction: column;
73
+ gap: var(--panneau-space-1);
74
+ }
75
+
64
76
  .panneau-displays-thumbnail {
65
77
  flex: none;
66
78
  width: 2.5rem;
@@ -69,3 +81,39 @@
69
81
  background-color: var(--panneau-color-surface-sunken);
70
82
  border-radius: var(--panneau-radius-sm);
71
83
  }
84
+
85
+ .panneau-displays-code {
86
+ font-family: var(--panneau-font-family-mono);
87
+ font-size: var(--panneau-font-size-sm);
88
+ white-space: nowrap;
89
+ }
90
+
91
+ .panneau-displays-tags {
92
+ display: inline-flex;
93
+ flex-wrap: wrap;
94
+ gap: var(--panneau-space-1);
95
+ }
96
+
97
+ /* Several countries. */
98
+ .panneau-displays-countries {
99
+ display: inline-flex;
100
+ flex-wrap: wrap;
101
+ gap: var(--panneau-space-1) var(--panneau-space-3);
102
+ }
103
+
104
+ /* A value after a flag: a country, a region, a phone number. */
105
+ .panneau-displays-flagged {
106
+ display: inline-flex;
107
+ align-items: baseline;
108
+ gap: var(--panneau-space-2);
109
+ min-width: 0;
110
+ }
111
+
112
+ .panneau-displays-flag {
113
+ flex: 0 0 auto;
114
+ }
115
+
116
+ /* The flag of a region is an image: centered on the text, where an emoji sits on its baseline. */
117
+ .panneau-displays-region-flag {
118
+ align-self: center;
119
+ }
@@ -7,9 +7,17 @@ var boolean = "panneau-displays-boolean";
7
7
  var number = "panneau-displays-number";
8
8
  var link = "panneau-displays-link";
9
9
  var color = "panneau-displays-color";
10
+ var paletteColor = "panneau-displays-palette-color";
10
11
  var swatch = "panneau-displays-swatch";
11
12
  var media = "panneau-displays-media";
13
+ var files = "panneau-displays-files";
12
14
  var thumbnail = "panneau-displays-thumbnail";
15
+ var code = "panneau-displays-code";
16
+ var tags = "panneau-displays-tags";
17
+ var countries = "panneau-displays-countries";
18
+ var flagged = "panneau-displays-flagged";
19
+ var flag = "panneau-displays-flag";
20
+ var regionFlag = "panneau-displays-region-flag";
13
21
  var Displays_module_default = {
14
22
  empty,
15
23
  text,
@@ -20,11 +28,19 @@ var Displays_module_default = {
20
28
  number,
21
29
  link,
22
30
  color,
31
+ paletteColor,
23
32
  swatch,
24
33
  media,
25
- thumbnail
34
+ files,
35
+ thumbnail,
36
+ code,
37
+ tags,
38
+ countries,
39
+ flagged,
40
+ flag,
41
+ regionFlag
26
42
  };
27
43
  //#endregion
28
- export { badges, boolean, color, Displays_module_default as default, empty, link, media, number, swatch, text, thumbnail };
44
+ export { badges, boolean, code, color, countries, Displays_module_default as default, empty, files, flag, flagged, link, media, number, paletteColor, regionFlag, swatch, tags, text, thumbnail };
29
45
 
30
46
  //# sourceMappingURL=Displays.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Displays.module.js","names":[],"sources":["../../src/displays/Displays.module.css"],"sourcesContent":[".empty {\n color: var(--panneau-color-text-muted);\n}\n\n.text {\n display: -webkit-box;\n overflow: hidden;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow-wrap: anywhere;\n}\n\n.badges {\n display: inline-flex;\n flex-wrap: wrap;\n gap: var(--panneau-space-1);\n}\n\n.boolean {\n display: inline-flex;\n align-items: center;\n}\n\n.true {\n color: var(--panneau-color-success);\n}\n\n.false {\n color: var(--panneau-color-text-muted);\n}\n\n.number {\n font-variant-numeric: var(--panneau-font-numeric);\n}\n\n.link {\n color: var(--panneau-color-link);\n overflow-wrap: anywhere;\n}\n\n.color {\n display: inline-flex;\n align-items: center;\n gap: var(--panneau-space-2);\n font-family: var(--panneau-font-family-mono);\n font-size: var(--panneau-font-size-sm);\n}\n\n.swatch {\n flex: none;\n width: 1rem;\n height: 1rem;\n border: var(--panneau-border-width) solid var(--panneau-color-border-control);\n border-radius: var(--panneau-radius-sm);\n}\n\n.media {\n display: inline-flex;\n align-items: center;\n gap: var(--panneau-space-2);\n}\n\n.thumbnail {\n flex: none;\n width: 2.5rem;\n height: 2.5rem;\n object-fit: cover;\n background-color: var(--panneau-color-surface-sunken);\n border-radius: var(--panneau-radius-sm);\n}\n"],"mappings":""}
1
+ {"version":3,"file":"Displays.module.js","names":[],"sources":["../../src/displays/Displays.module.css"],"sourcesContent":[".empty {\n color: var(--panneau-color-text-muted);\n}\n\n.text {\n display: -webkit-box;\n overflow: hidden;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow-wrap: anywhere;\n}\n\n.badges {\n display: inline-flex;\n flex-wrap: wrap;\n gap: var(--panneau-space-1);\n}\n\n.boolean {\n display: inline-flex;\n align-items: center;\n}\n\n.true {\n color: var(--panneau-color-success);\n}\n\n.false {\n color: var(--panneau-color-text-muted);\n}\n\n.number {\n font-variant-numeric: var(--panneau-font-numeric);\n}\n\n.link {\n color: var(--panneau-color-link);\n overflow-wrap: anywhere;\n}\n\n.color {\n display: inline-flex;\n align-items: center;\n gap: var(--panneau-space-2);\n font-family: var(--panneau-font-family-mono);\n font-size: var(--panneau-font-size-sm);\n}\n\n.paletteColor {\n display: inline-flex;\n align-items: center;\n gap: var(--panneau-space-2);\n}\n\n.swatch {\n flex: none;\n width: 1rem;\n height: 1rem;\n border: var(--panneau-border-width) solid var(--panneau-color-border-control);\n border-radius: var(--panneau-radius-sm);\n}\n\n.media {\n display: inline-flex;\n align-items: center;\n gap: var(--panneau-space-2);\n}\n\n.files {\n display: inline-flex;\n flex-direction: column;\n gap: var(--panneau-space-1);\n}\n\n.thumbnail {\n flex: none;\n width: 2.5rem;\n height: 2.5rem;\n object-fit: cover;\n background-color: var(--panneau-color-surface-sunken);\n border-radius: var(--panneau-radius-sm);\n}\n\n.code {\n font-family: var(--panneau-font-family-mono);\n font-size: var(--panneau-font-size-sm);\n white-space: nowrap;\n}\n\n.tags {\n display: inline-flex;\n flex-wrap: wrap;\n gap: var(--panneau-space-1);\n}\n\n/* Several countries. */\n.countries {\n display: inline-flex;\n flex-wrap: wrap;\n gap: var(--panneau-space-1) var(--panneau-space-3);\n}\n\n/* A value after a flag: a country, a region, a phone number. */\n.flagged {\n display: inline-flex;\n align-items: baseline;\n gap: var(--panneau-space-2);\n min-width: 0;\n}\n\n.flag {\n flex: 0 0 auto;\n}\n\n/* The flag of a region is an image: centered on the text, where an emoji sits on its baseline. */\n.regionFlag {\n align-self: center;\n}\n"],"mappings":""}