@limetech/lime-elements 38.28.0 → 38.28.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## [38.28.2](https://github.com/Lundalogik/lime-elements/compare/v38.28.1...v38.28.2) (2025-10-15)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+
7
+ * **list:** prevent double `interact` event emits, when an item is clicked ([7672994](https://github.com/Lundalogik/lime-elements/commit/7672994ce1e44f6d39afea841656a0ee4c2ddd09))
8
+
9
+ ## [38.28.1](https://github.com/Lundalogik/lime-elements/compare/v38.28.0...v38.28.1) (2025-10-15)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+
15
+ * **text editor:** add noopener/noreferrer for security ([7109ac8](https://github.com/Lundalogik/lime-elements/commit/7109ac86b57bb60c33c4366b489521e40292649f))
16
+ * **text editor:** guard against potential null destructuring ([c1d4d4f](https://github.com/Lundalogik/lime-elements/commit/c1d4d4fedf5197bbfc7554c9286a138d2ed880fe))
17
+ * **text editor:** mousedown handling should only return true once handled ([3a81f98](https://github.com/Lundalogik/lime-elements/commit/3a81f98d2af3d3f2ffba4a16aafde24183f2742d))
18
+ * **text editor:** only open popup to edit link on double click ([d78f408](https://github.com/Lundalogik/lime-elements/commit/d78f408fab30428a84559683a3e20d6eca65668c))
19
+ * **text editor:** preserve linebreaks when handling paste events ([80d1cde](https://github.com/Lundalogik/lime-elements/commit/80d1cde244c5586c8ae087ac65087913b0d07fdd))
20
+
1
21
  ## [38.28.0](https://github.com/Lundalogik/lime-elements/compare/v38.27.0...v38.28.0) (2025-10-07)
2
22
 
3
23
 
package/README.md CHANGED
@@ -23,6 +23,15 @@ Whether you're building from scratch or enhancing existing applications, Lime El
23
23
 
24
24
  Visit our [📚 **Documentation**](https://lundalogik.github.io/lime-elements/) for comprehensive guides and examples, or install directly from [📦 **NPM**](https://www.npmjs.com/package/@limetech/lime-elements).
25
25
 
26
+ ---
27
+
28
+ ### Recent Updates
29
+
30
+ - 🆕 **What's New:** Get an overview of the recent [most noteworthy updates and features](https://lundalogik.github.io/lime-elements/versions/latest/#/Home/updates.md/)
31
+ - 📋 **Changelog:** Check our [changelog](https://github.com/Lundalogik/lime-elements/blob/main/CHANGELOG.md) for detailed info about the new features, bug fixes, and design improvements
32
+
33
+ ---
34
+
26
35
  ### Project Status
27
36
 
28
37
  [![Version](https://img.shields.io/npm/v/@limetech/lime-elements.svg)](https://www.npmjs.com/package/@limetech/lime-elements) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![npm downloads](https://img.shields.io/npm/dt/@limetech/lime-elements.svg)](https://www.npmjs.com/package/@limetech/lime-elements)
@@ -138,7 +147,7 @@ Remember: All components can change, but `@beta` components change more often an
138
147
  - 💬 **Questions?** [create an issue](https://github.com/Lundalogik/lime-elements/issues/new?template=03_question.md)
139
148
  - 🐛 **Found a bug?** [Report it here](https://github.com/Lundalogik/lime-elements/issues/new?template=01_bug_report.md)
140
149
  - 💡 **Feature request?** [Share your ideas](https://github.com/Lundalogik/lime-elements/issues/new?template=02_feature_request.md)
141
- - 🆕 **What's new?** Check our [changelog](https://github.com/Lundalogik/lime-elements/blob/main/CHANGELOG.md) for the latest updates
150
+ - 🆕 **Changelog** Check our [changelog](https://github.com/Lundalogik/lime-elements/blob/main/CHANGELOG.md) for detailed info about the new features, bug fixes, and design improvements
142
151
 
143
152
  ---
144
153
 
@@ -25,7 +25,6 @@ const listItemCss = "@charset \"UTF-8\";*,*:before,*:after{box-sizing:border-box
25
25
  const ListItemComponent = class {
26
26
  constructor(hostRef) {
27
27
  index.registerInstance(this, hostRef);
28
- this.interact = index.createEvent(this, "interact", 7);
29
28
  this.renderLabel = () => {
30
29
  return (index.h("span", { class: "label", id: this.labelId }, this.text));
31
30
  };
@@ -95,84 +94,6 @@ const ListItemComponent = class {
95
94
  }
96
95
  return (index.h(checkbox_template.CheckboxTemplate, { id: `checkbox_${this.labelId}`, checked: this.selected, disabled: this.disabled }));
97
96
  };
98
- this.onClick = (event) => {
99
- if (this.disabled) {
100
- // Ignore toggling, but don't block embedded controls
101
- return;
102
- }
103
- const target = event.target;
104
- const cameFromActionTrigger = !!(target === null || target === void 0 ? void 0 : target.closest('.action-menu-trigger'));
105
- const cameFromNoToggle = !!(target === null || target === void 0 ? void 0 : target.closest('[data-no-toggle]'));
106
- const cameFromMenu = !!(target === null || target === void 0 ? void 0 : target.closest('limel-menu'));
107
- if (cameFromActionTrigger || cameFromNoToggle || cameFromMenu) {
108
- return;
109
- }
110
- if (this.isSelectableType()) {
111
- this.handleInteraction();
112
- }
113
- // For non-selectable types (menuitem/listitem), allow native click to bubble
114
- };
115
- this.onKeyDown = (event) => {
116
- if (this.disabled) {
117
- return;
118
- }
119
- // Only handle keyboard when the host itself has focus.
120
- // This avoids toggling when Space/Enter is pressed on inner controls
121
- // like the action menu trigger or any primary component.
122
- const shadowRoot = this.host.shadowRoot;
123
- const activeElement = shadowRoot
124
- ? shadowRoot.activeElement
125
- : null;
126
- if (activeElement && activeElement !== this.host) {
127
- return;
128
- }
129
- const isEnter = event.key === 'Enter';
130
- const isSpace = event.key === ' ' ||
131
- event.key === 'Space' ||
132
- event.key === 'Spacebar' ||
133
- event.code === 'Space';
134
- if (!isEnter && !isSpace) {
135
- return;
136
- }
137
- // Avoid re-triggering while key is held down and auto-repeats
138
- if (event.repeat) {
139
- // Also prevent default scroll on Space when repeating
140
- if (isSpace) {
141
- event.preventDefault();
142
- }
143
- return;
144
- }
145
- // Prevent page scroll and default button behavior on Space
146
- if (isSpace) {
147
- event.preventDefault();
148
- }
149
- if (this.isSelectableType()) {
150
- this.handleInteraction();
151
- return;
152
- }
153
- // For non-selectable items, treat Enter and Space as activation (simulate click)
154
- if (isEnter || isSpace) {
155
- this.host.click();
156
- }
157
- };
158
- this.handleInteraction = () => {
159
- const newSelected = !this.selected;
160
- const item = {
161
- text: this.text,
162
- secondaryText: this.secondaryText,
163
- disabled: this.disabled,
164
- icon: this.icon,
165
- selected: newSelected,
166
- value: this.value,
167
- actions: this.actions,
168
- primaryComponent: this.primaryComponent,
169
- image: this.image,
170
- };
171
- this.interact.emit({
172
- selected: newSelected,
173
- item: item,
174
- });
175
- };
176
97
  this.actionMenuLabel = () => {
177
98
  return translations.translate.get('file-viewer.more-actions', this.language);
178
99
  };
@@ -212,7 +133,7 @@ const ListItemComponent = class {
212
133
  }
213
134
  return (index.h(index.Host, Object.assign({ role: this.getHostRole(), class: {
214
135
  'has-primary-component': !!((_a = this.primaryComponent) === null || _a === void 0 ? void 0 : _a.name),
215
- } }, ariaProps, { onClick: this.onClick, onKeyDown: this.onKeyDown }), this.renderRadioButton(), this.renderCheckbox(), this.renderIcon(), this.renderImage(), this.renderPrimaryComponent(), index.h("div", { class: "text" }, this.renderLabel(), this.renderDescription()), this.renderActionMenu(this.actions)));
136
+ } }, ariaProps), this.renderRadioButton(), this.renderCheckbox(), this.renderIcon(), this.renderImage(), this.renderPrimaryComponent(), index.h("div", { class: "text" }, this.renderLabel(), this.renderDescription()), this.renderActionMenu(this.actions)));
216
137
  }
217
138
  /**
218
139
  * Returns a stable reference for the provided actions array to avoid
@@ -228,11 +149,6 @@ const ListItemComponent = class {
228
149
  this.memoizedActions = actions;
229
150
  return actions;
230
151
  }
231
- isSelectableType() {
232
- return (this.type === 'option' ||
233
- this.type === 'radio' ||
234
- this.type === 'checkbox');
235
- }
236
152
  getHostRole() {
237
153
  switch (this.type) {
238
154
  case 'option': {
@@ -252,7 +168,6 @@ const ListItemComponent = class {
252
168
  }
253
169
  }
254
170
  }
255
- get host() { return index.getElement(this); }
256
171
  };
257
172
  ListItemComponent.style = listItemCss;
258
173
 
@@ -1 +1 @@
1
- {"file":"limel-list-item.entry.cjs.js","mappings":"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","names":["h","getIconName","CheckboxTemplate","translate","createRandomString","Host"],"sources":["./src/components/radio-button-group/radio-button.template.tsx","./src/components/list-item/list-item.scss?tag=limel-list-item","./src/components/list-item/list-item.tsx"],"sourcesContent":["import { FunctionalComponent, h } from '@stencil/core';\n\n/**\n * Radio Button Template\n *\n * This is a low-level template component that renders individual radio button elements\n * using Material Design Components (MDC) styling and structure. It's used internally\n * by the list component to render radio buttons when `type=\"radio\"` is specified.\n *\n * ## Usage in the Library\n *\n * This template is primarily used by:\n * - `limel-list` component when `type=\"radio\"`\n * - `limel-radio-button-group` component (which wraps `limel-list`)\n *\n * ## Why This Exists\n *\n * While we have `limel-radio-button-group` for most use cases, this template provides\n * the actual radio button HTML structure with proper MDC classes and accessibility\n * attributes. It ensures consistent styling and behavior across all radio button\n * implementations in the library.\n *\n * ## Design Philosophy\n *\n * This follows the principle that individual radio buttons should not be standalone\n * components, as a single radio button is never useful in a UI. Instead, this template\n * is used to build groups of radio buttons through higher-level components.\n *\n * @internal\n */\ninterface RadioButtonTemplateProps {\n disabled?: boolean;\n id: string;\n checked?: boolean;\n onChange?: (event: Event) => void;\n label?: string;\n}\n\nexport const RadioButtonTemplate: FunctionalComponent<\n RadioButtonTemplateProps\n> = (props) => {\n return (\n <div\n class={{\n 'boolean-input': true,\n 'radio-button': true,\n checked: props.checked,\n disabled: props.disabled,\n }}\n >\n <input\n type=\"radio\"\n id={props.id}\n checked={props.checked}\n disabled={props.disabled}\n onChange={props.onChange}\n />\n <div class=\"box\" />\n <label class=\"boolean-input-label\" htmlFor={props.id}>\n {props.label}\n </label>\n </div>\n );\n};\n","/**\n * @prop --notification-badge-text-color: (Publicly documented in `limel-menu` too) Defines the text color of notification badges. Defaults to `--color-white`.\n * @prop --notification-badge-background-color: (Publicly documented in `limel-menu` too) Defines the background color of notification badges. Defaults to `--color-red-default`.\n * @prop --limel-list-item-menu-order: Defines the order of the menu, within the list item's flexbox. Defaults to `3`.\n */\n\n@use '../../style/mixins';\n@forward '../checkbox/checkbox.scss';\n@forward '../radio-button-group/radio-button.scss';\n\n*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nlimel-list-item {\n min-height: 2.5rem;\n @include mixins.visualize-keyboard-focus();\n\n transition: background-color 0.6s ease;\n position: relative;\n isolation: isolate;\n\n display: flex;\n align-items: center;\n gap: 0.5rem;\n\n padding: 0 1rem;\n background-color: rgb(var(--contrast-100));\n\n &:hover {\n z-index: 1;\n transition: background-color 0.2s ease;\n border-radius: 0.5rem;\n }\n\n &:focus,\n &:focus-visible,\n &:active {\n z-index: 1;\n border-radius: 0.5rem;\n }\n\n &:first-of-type {\n border-top-left-radius: 0.5rem;\n border-top-right-radius: 0.5rem;\n }\n\n &:last-of-type {\n border-bottom-left-radius: 0.5rem;\n border-bottom-right-radius: 0.5rem;\n }\n\n &:not([disabled]):not([disabled='true']) {\n cursor: pointer;\n }\n\n &[disabled]:not([disabled='false']) {\n cursor: not-allowed;\n }\n}\n\nlimel-list-item[disabled]:not([disabled='false']) {\n cursor: not-allowed;\n\n .text,\n limel-icon,\n img,\n .boolean-input {\n opacity: 0.4;\n }\n}\n\nlimel-list-item:not([disabled]):not([disabled='true']):hover,\nlimel-list-item:not([disabled]):not([disabled='true']):focus-visible {\n background-color: rgb(var(--contrast-400));\n}\n\nlimel-list-item[type='option'] {\n &:before {\n transition: background-color 0.6s ease;\n content: '';\n position: absolute;\n inset: 0;\n\n opacity: 0.2;\n border-radius: 0.5rem;\n }\n\n &[selected]:not([selected='false']) {\n &:before {\n transition: background-color 0.2s ease;\n background-color: var(--limel-theme-primary-color);\n }\n }\n}\n\nlimel-list-item {\n .text {\n flex-grow: 1;\n min-width: 0;\n\n display: flex;\n flex-direction: column;\n\n padding: 0.5rem 0;\n\n color: var(--limel-theme-text-primary-on-background-color);\n }\n\n .label {\n @include mixins.truncate-text();\n\n font-size: var(--limel-theme-default-font-size);\n line-height: 1rem;\n }\n\n .description {\n @include mixins.truncate-text-on-line(var(--maxLinesSecondaryText));\n line-height: 1rem;\n font-size: var(--limel-theme-default-small-font-size);\n opacity: 0.6;\n }\n\n limel-icon {\n color: var(--limel-theme-text-secondary-on-background-color);\n flex-shrink: 0;\n margin-left: -0.5rem;\n\n &:has(+ img) {\n margin-left: 0;\n position: absolute;\n top: 0.125rem;\n left: 0.125rem;\n padding: 0.1875rem;\n width: 1.25rem;\n background-color: rgb(var(--contrast-200), 0.8);\n }\n }\n\n img {\n flex-shrink: 0;\n object-fit: cover;\n border-radius: 50%;\n width: 2rem;\n height: 2rem;\n box-shadow: 0 0 0 1px rgb(var(--contrast-800), 0.5);\n }\n\n limel-menu {\n margin-right: -0.5rem;\n // Sometimes, `primaryComponent`s in list items need to get\n // `order: 2;` to be placed after the text. But since the default `order`\n // of all lit item children is `0`, we need to push the menu to the far right\n // by giving it a bigger order number. Also, by making this into a variable\n // we can handle other edge-cases in consuming components.\n order: var(--limel-list-item-menu-order, 3);\n }\n}\n\nlimel-list-item {\n &[role='menuitem'] & {\n .label {\n font-size: var(--limel-theme-default-small-font-size);\n }\n }\n}\n\n// ====================\n// Checkbox and radios\n.boolean-input {\n width: var(--limel-boolean-input-box-size);\n margin-left: -0.25rem;\n &.checkbox {\n margin-right: 0.25rem;\n }\n\n limel-list-item:has(limel-icon) &,\n limel-list-item:has(img) & {\n margin-right: -0.25rem;\n margin-left: 0;\n order: 2;\n }\n}\n\n.boolean-input-label {\n @include mixins.truncate-text();\n opacity: 0;\n width: var(--limel-boolean-input-box-size);\n}\n// ====================\n","import {\n Component,\n Host,\n Prop,\n h,\n Event,\n EventEmitter,\n Element,\n} from '@stencil/core';\nimport { getIconName } from '../icon/get-icon-props';\nimport type { IconSize } from '../icon/icon.types';\nimport { createRandomString } from '../../util/random-string';\nimport { ListItem } from './list-item.types';\nimport { MenuItem } from '../menu/menu.types';\nimport { ListSeparator } from '../../global/shared-types/separator.types';\nimport { CheckboxTemplate } from '../checkbox/checkbox.template';\nimport { RadioButtonTemplate } from '../radio-button-group/radio-button.template';\nimport translate from '../../global/translations';\nimport { Languages } from '../date-picker/date.types';\n\n/**\n * This components displays the list item.\n * This centralizes styles and functionality, and helps reduce redundant code\n * in consumer components such as `limel-list` and `limel-menu-list`.\n *\n * :::note\n * The component has `shadow: false`. There are a few reasons for it:\n * 1. This is to improve performance, and ensure that its internal elements are\n * considered as internal parts of the consumer's DOM.\n * 2. The consumer does not need to implement the interactive styles\n * (such as `visualize-keyboard-focus` mixin) on their own. Since there is no\n * shadow DOM, our mixins can be applied directly to the `limel-list-item` elements,\n * within the component's own styles.\n * 3. Most importantly, the MDCList checks the light DOM of each list item\n * to find native inputs to decide the list mode (checkbox/radio).\n * With `shadow: true`, those inputs would be hidden inside the `limel-list-items`’s\n * shadow DOM, so MDC wouldn’t detect them and therefore throw errors, when given\n * an array index (for the items).\n * With `shadow: false`, the native `<input type=\"checkbox/radio\">` from this template\n * would be visible to MDC.\n * :::\n * @exampleComponent limel-example-list-item-basic\n * @exampleComponent limel-example-list-item-icon\n * @exampleComponent limel-example-list-item-icon-size\n * @exampleComponent limel-example-list-item-pictures\n * @exampleComponent limel-example-list-item-multiple-lines\n * @exampleComponent limel-example-list-item-interactive\n * @exampleComponent limel-example-list-item-radio\n * @exampleComponent limel-example-list-item-checkbox\n * @exampleComponent limel-example-list-item-actions\n * @exampleComponent limel-example-list-item-primary-component\n * @exampleComponent limel-example-list-item-command-text\n * @private\n */\n@Component({\n tag: 'limel-list-item',\n shadow: false,\n styleUrl: 'list-item.scss',\n})\nexport class ListItemComponent implements ListItem {\n /**\n * Defines the language for translations.\n * Will translate the translatable strings on the components.\n */\n @Prop({ reflect: true })\n public language: Languages = 'en';\n\n /**\n * {@inheritdoc ListItem.value}\n */\n @Prop()\n public value?: any;\n\n /**\n * {@inheritdoc ListItem.text}\n */\n @Prop({ reflect: true })\n public text: string;\n\n /**\n * {@inheritdoc ListItem.secondaryText}\n */\n @Prop({ reflect: true })\n public secondaryText?: string;\n\n /**\n * {@inheritdoc ListItem.disabled}\n */\n @Prop({ reflect: true })\n public disabled = false;\n\n /**\n * {@inheritdoc ListItem.icon}\n */\n @Prop()\n public icon?: string | ListItem['icon'];\n\n /**\n * Size of the icon displayed for this item.\n */\n @Prop({ reflect: true })\n public iconSize: IconSize = 'small';\n\n /**\n * Set to `true` if the list should display larger icons with a background\n */\n @Prop({ reflect: true })\n public badgeIcon = false;\n\n /**\n * {@inheritdoc ListItem.selected}\n */\n @Prop({ reflect: true })\n public selected = false;\n\n /**\n * {@inheritdoc ListItem.selected}\n */\n @Prop()\n public actions?: ListItem['actions'];\n\n /**\n * {@inheritdoc ListItem.selected}\n */\n @Prop()\n public primaryComponent?: ListItem['primaryComponent'];\n\n /**\n * {@inheritdoc ListItem.image}\n */\n @Prop()\n public image?: ListItem['image'];\n\n /**\n * The semantic role of the list item. This affects the ARIA role\n * and the interaction behavior.\n *\n * - 'option' → selectable via click/Enter/Space, aria-selected\n * - 'radio'/'checkbox' → selectable, aria-checked\n * - 'menuitem'/'listitem' → activation only, no selection toggle\n */\n @Prop({ reflect: true })\n public type: 'listitem' | 'menuitem' | 'option' | 'radio' | 'checkbox' =\n 'listitem';\n\n /**\n * Emitted when the list item toggles selection (only for selectable types and not disabled).\n */\n @Event()\n public interact: EventEmitter<{\n selected: boolean;\n item: ListItem;\n }>;\n\n @Element()\n private host: HTMLLimelListItemElement;\n\n /**\n * Used to describe the list item for assistive technology.\n */\n private readonly descriptionId: string;\n\n /**\n * Used to label the list item for assistive technology.\n */\n private readonly labelId: string;\n\n // Memoized reference for the action items to avoid unnecessary updates\n private memoizedActions?: Array<MenuItem | ListSeparator>;\n\n constructor() {\n this.labelId = createRandomString();\n this.descriptionId = createRandomString();\n }\n\n public render() {\n const ariaProps: any = {\n 'aria-labelledby': this.labelId,\n 'aria-describedby': this.secondaryText\n ? this.descriptionId\n : undefined,\n 'aria-disabled': this.disabled ? 'true' : 'false',\n };\n\n // ARIA state depending on `role`/`type`\n if (this.type === 'radio' || this.type === 'checkbox') {\n ariaProps['aria-checked'] = this.selected ? 'true' : 'false';\n } else if (this.type === 'option' || this.type === 'menuitem') {\n // aria-selected for `option` (spec);\n // also keep for `menuitem` for visual state consistency\n ariaProps['aria-selected'] = this.selected ? 'true' : 'false';\n }\n\n return (\n <Host\n role={this.getHostRole()}\n class={{\n 'has-primary-component': !!this.primaryComponent?.name,\n }}\n {...ariaProps}\n onClick={this.onClick}\n onKeyDown={this.onKeyDown}\n >\n {this.renderRadioButton()}\n {this.renderCheckbox()}\n {this.renderIcon()}\n {this.renderImage()}\n {this.renderPrimaryComponent()}\n <div class=\"text\">\n {this.renderLabel()}\n {this.renderDescription()}\n </div>\n {this.renderActionMenu(this.actions)}\n </Host>\n );\n }\n\n private renderLabel = () => {\n return (\n <span class=\"label\" id={this.labelId}>\n {this.text}\n </span>\n );\n };\n\n private renderDescription = () => {\n if (!this.secondaryText) {\n return;\n }\n\n return (\n <span class=\"description\" id={this.descriptionId}>\n {this.secondaryText}\n </span>\n );\n };\n\n private renderIcon = () => {\n const iconName = getIconName(this.icon);\n if (!iconName) {\n return;\n }\n\n let iconColor: string | undefined;\n let iconBackgroundColor: string | undefined;\n let title: string | undefined;\n\n if (typeof this.icon === 'object') {\n iconColor = this.icon.color;\n iconBackgroundColor = this.icon.backgroundColor;\n title = this.icon.title;\n }\n\n const iconProps = {\n 'aria-label': title,\n 'aria-hidden': title ? null : 'true',\n name: iconName,\n style: {\n color: iconColor,\n 'background-color': iconBackgroundColor,\n },\n badge: this.badgeIcon,\n size: this.iconSize,\n };\n\n return <limel-icon {...iconProps} />;\n };\n\n private renderPrimaryComponent = () => {\n const primary = this.primaryComponent;\n if (!primary?.name) {\n return;\n }\n\n const PrimaryComponent: any = primary.name;\n const props = primary.props || {};\n\n return <PrimaryComponent {...props} />;\n };\n\n private renderImage = () => {\n if (!this.image) {\n return;\n }\n\n return <img src={this.image.src} alt={this.image.alt} loading=\"lazy\" />;\n };\n\n private renderActionMenu = (actions: Array<MenuItem | ListSeparator>) => {\n if (!actions || actions.length === 0) {\n return;\n }\n\n const stableActions = this.getStableActions(actions);\n return (\n <limel-menu\n class=\"mdc-deprecated-list-item__meta\"\n items={stableActions}\n openDirection=\"left-start\"\n >\n <limel-icon-button\n class=\"action-menu-trigger\"\n slot=\"trigger\"\n icon=\"menu_2\"\n label={this.actionMenuLabel()}\n />\n </limel-menu>\n );\n };\n\n /**\n * Returns a stable reference for the provided actions array to avoid\n * unnecessary re-renders of the action menu when the reference is unchanged.\n *\n * @param actions The actions (and separators) to display in the menu\n * @returns The same array instance that was previously seen, if unchanged\n */\n private getStableActions(\n actions: Array<MenuItem | ListSeparator>\n ): Array<MenuItem | ListSeparator> {\n if (this.memoizedActions === actions) {\n return this.memoizedActions;\n }\n this.memoizedActions = actions;\n return actions;\n }\n\n private renderRadioButton = () => {\n if (this.type !== 'radio') {\n return;\n }\n\n return (\n <RadioButtonTemplate\n id={`radio_${this.labelId}`}\n checked={this.selected}\n disabled={this.disabled}\n />\n );\n };\n\n private renderCheckbox = () => {\n if (this.type !== 'checkbox') {\n return;\n }\n\n return (\n <CheckboxTemplate\n id={`checkbox_${this.labelId}`}\n checked={this.selected}\n disabled={this.disabled}\n />\n );\n };\n\n private onClick = (event: MouseEvent) => {\n if (this.disabled) {\n // Ignore toggling, but don't block embedded controls\n return;\n }\n\n const target = event.target as HTMLElement | null;\n const cameFromActionTrigger = !!target?.closest('.action-menu-trigger');\n const cameFromNoToggle = !!target?.closest('[data-no-toggle]');\n const cameFromMenu = !!target?.closest('limel-menu');\n if (cameFromActionTrigger || cameFromNoToggle || cameFromMenu) {\n return;\n }\n\n if (this.isSelectableType()) {\n this.handleInteraction();\n }\n // For non-selectable types (menuitem/listitem), allow native click to bubble\n };\n\n private onKeyDown = (event: KeyboardEvent) => {\n if (this.disabled) {\n return;\n }\n\n // Only handle keyboard when the host itself has focus.\n // This avoids toggling when Space/Enter is pressed on inner controls\n // like the action menu trigger or any primary component.\n const shadowRoot = this.host.shadowRoot;\n const activeElement = shadowRoot\n ? (shadowRoot.activeElement as HTMLElement | null)\n : null;\n if (activeElement && activeElement !== this.host) {\n return;\n }\n\n const isEnter = event.key === 'Enter';\n const isSpace =\n event.key === ' ' ||\n event.key === 'Space' ||\n event.key === 'Spacebar' ||\n event.code === 'Space';\n\n if (!isEnter && !isSpace) {\n return;\n }\n\n // Avoid re-triggering while key is held down and auto-repeats\n if (event.repeat) {\n // Also prevent default scroll on Space when repeating\n if (isSpace) {\n event.preventDefault();\n }\n return;\n }\n\n // Prevent page scroll and default button behavior on Space\n if (isSpace) {\n event.preventDefault();\n }\n\n if (this.isSelectableType()) {\n this.handleInteraction();\n return;\n }\n\n // For non-selectable items, treat Enter and Space as activation (simulate click)\n if (isEnter || isSpace) {\n this.host.click();\n }\n };\n\n private isSelectableType(): boolean {\n return (\n this.type === 'option' ||\n this.type === 'radio' ||\n this.type === 'checkbox'\n );\n }\n\n private getHostRole(): string {\n switch (this.type) {\n case 'option': {\n return 'option';\n }\n case 'radio': {\n return 'radio';\n }\n case 'checkbox': {\n return 'checkbox';\n }\n case 'menuitem': {\n return 'menuitem';\n }\n default: {\n return 'listitem';\n }\n }\n }\n\n private handleInteraction = () => {\n const newSelected = !this.selected;\n\n const item: ListItem = {\n text: this.text,\n secondaryText: this.secondaryText,\n disabled: this.disabled,\n icon: this.icon,\n selected: newSelected,\n value: this.value,\n actions: this.actions,\n primaryComponent: this.primaryComponent,\n image: this.image,\n };\n\n this.interact.emit({\n selected: newSelected,\n item: item,\n });\n };\n\n private actionMenuLabel = (): string => {\n return translate.get('file-viewer.more-actions', this.language);\n };\n}\n"],"version":3}
1
+ {"file":"limel-list-item.entry.cjs.js","mappings":"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","names":["h","getIconName","CheckboxTemplate","translate","createRandomString","Host"],"sources":["./src/components/radio-button-group/radio-button.template.tsx","./src/components/list-item/list-item.scss?tag=limel-list-item","./src/components/list-item/list-item.tsx"],"sourcesContent":["import { FunctionalComponent, h } from '@stencil/core';\n\n/**\n * Radio Button Template\n *\n * This is a low-level template component that renders individual radio button elements\n * using Material Design Components (MDC) styling and structure. It's used internally\n * by the list component to render radio buttons when `type=\"radio\"` is specified.\n *\n * ## Usage in the Library\n *\n * This template is primarily used by:\n * - `limel-list` component when `type=\"radio\"`\n * - `limel-radio-button-group` component (which wraps `limel-list`)\n *\n * ## Why This Exists\n *\n * While we have `limel-radio-button-group` for most use cases, this template provides\n * the actual radio button HTML structure with proper MDC classes and accessibility\n * attributes. It ensures consistent styling and behavior across all radio button\n * implementations in the library.\n *\n * ## Design Philosophy\n *\n * This follows the principle that individual radio buttons should not be standalone\n * components, as a single radio button is never useful in a UI. Instead, this template\n * is used to build groups of radio buttons through higher-level components.\n *\n * @internal\n */\ninterface RadioButtonTemplateProps {\n disabled?: boolean;\n id: string;\n checked?: boolean;\n onChange?: (event: Event) => void;\n label?: string;\n}\n\nexport const RadioButtonTemplate: FunctionalComponent<\n RadioButtonTemplateProps\n> = (props) => {\n return (\n <div\n class={{\n 'boolean-input': true,\n 'radio-button': true,\n checked: props.checked,\n disabled: props.disabled,\n }}\n >\n <input\n type=\"radio\"\n id={props.id}\n checked={props.checked}\n disabled={props.disabled}\n onChange={props.onChange}\n />\n <div class=\"box\" />\n <label class=\"boolean-input-label\" htmlFor={props.id}>\n {props.label}\n </label>\n </div>\n );\n};\n","/**\n * @prop --notification-badge-text-color: (Publicly documented in `limel-menu` too) Defines the text color of notification badges. Defaults to `--color-white`.\n * @prop --notification-badge-background-color: (Publicly documented in `limel-menu` too) Defines the background color of notification badges. Defaults to `--color-red-default`.\n * @prop --limel-list-item-menu-order: Defines the order of the menu, within the list item's flexbox. Defaults to `3`.\n */\n\n@use '../../style/mixins';\n@forward '../checkbox/checkbox.scss';\n@forward '../radio-button-group/radio-button.scss';\n\n*,\n*:before,\n*:after {\n box-sizing: border-box;\n}\n\nlimel-list-item {\n min-height: 2.5rem;\n @include mixins.visualize-keyboard-focus();\n\n transition: background-color 0.6s ease;\n position: relative;\n isolation: isolate;\n\n display: flex;\n align-items: center;\n gap: 0.5rem;\n\n padding: 0 1rem;\n background-color: rgb(var(--contrast-100));\n\n &:hover {\n z-index: 1;\n transition: background-color 0.2s ease;\n border-radius: 0.5rem;\n }\n\n &:focus,\n &:focus-visible,\n &:active {\n z-index: 1;\n border-radius: 0.5rem;\n }\n\n &:first-of-type {\n border-top-left-radius: 0.5rem;\n border-top-right-radius: 0.5rem;\n }\n\n &:last-of-type {\n border-bottom-left-radius: 0.5rem;\n border-bottom-right-radius: 0.5rem;\n }\n\n &:not([disabled]):not([disabled='true']) {\n cursor: pointer;\n }\n\n &[disabled]:not([disabled='false']) {\n cursor: not-allowed;\n }\n}\n\nlimel-list-item[disabled]:not([disabled='false']) {\n cursor: not-allowed;\n\n .text,\n limel-icon,\n img,\n .boolean-input {\n opacity: 0.4;\n }\n}\n\nlimel-list-item:not([disabled]):not([disabled='true']):hover,\nlimel-list-item:not([disabled]):not([disabled='true']):focus-visible {\n background-color: rgb(var(--contrast-400));\n}\n\nlimel-list-item[type='option'] {\n &:before {\n transition: background-color 0.6s ease;\n content: '';\n position: absolute;\n inset: 0;\n\n opacity: 0.2;\n border-radius: 0.5rem;\n }\n\n &[selected]:not([selected='false']) {\n &:before {\n transition: background-color 0.2s ease;\n background-color: var(--limel-theme-primary-color);\n }\n }\n}\n\nlimel-list-item {\n .text {\n flex-grow: 1;\n min-width: 0;\n\n display: flex;\n flex-direction: column;\n\n padding: 0.5rem 0;\n\n color: var(--limel-theme-text-primary-on-background-color);\n }\n\n .label {\n @include mixins.truncate-text();\n\n font-size: var(--limel-theme-default-font-size);\n line-height: 1rem;\n }\n\n .description {\n @include mixins.truncate-text-on-line(var(--maxLinesSecondaryText));\n line-height: 1rem;\n font-size: var(--limel-theme-default-small-font-size);\n opacity: 0.6;\n }\n\n limel-icon {\n color: var(--limel-theme-text-secondary-on-background-color);\n flex-shrink: 0;\n margin-left: -0.5rem;\n\n &:has(+ img) {\n margin-left: 0;\n position: absolute;\n top: 0.125rem;\n left: 0.125rem;\n padding: 0.1875rem;\n width: 1.25rem;\n background-color: rgb(var(--contrast-200), 0.8);\n }\n }\n\n img {\n flex-shrink: 0;\n object-fit: cover;\n border-radius: 50%;\n width: 2rem;\n height: 2rem;\n box-shadow: 0 0 0 1px rgb(var(--contrast-800), 0.5);\n }\n\n limel-menu {\n margin-right: -0.5rem;\n // Sometimes, `primaryComponent`s in list items need to get\n // `order: 2;` to be placed after the text. But since the default `order`\n // of all lit item children is `0`, we need to push the menu to the far right\n // by giving it a bigger order number. Also, by making this into a variable\n // we can handle other edge-cases in consuming components.\n order: var(--limel-list-item-menu-order, 3);\n }\n}\n\nlimel-list-item {\n &[role='menuitem'] & {\n .label {\n font-size: var(--limel-theme-default-small-font-size);\n }\n }\n}\n\n// ====================\n// Checkbox and radios\n.boolean-input {\n width: var(--limel-boolean-input-box-size);\n margin-left: -0.25rem;\n &.checkbox {\n margin-right: 0.25rem;\n }\n\n limel-list-item:has(limel-icon) &,\n limel-list-item:has(img) & {\n margin-right: -0.25rem;\n margin-left: 0;\n order: 2;\n }\n}\n\n.boolean-input-label {\n @include mixins.truncate-text();\n opacity: 0;\n width: var(--limel-boolean-input-box-size);\n}\n// ====================\n","import { Component, Host, Prop, h } from '@stencil/core';\nimport { getIconName } from '../icon/get-icon-props';\nimport type { IconSize } from '../icon/icon.types';\nimport { createRandomString } from '../../util/random-string';\nimport { ListItem } from './list-item.types';\nimport { MenuItem } from '../menu/menu.types';\nimport { ListSeparator } from '../../global/shared-types/separator.types';\nimport { CheckboxTemplate } from '../checkbox/checkbox.template';\nimport { RadioButtonTemplate } from '../radio-button-group/radio-button.template';\nimport translate from '../../global/translations';\nimport { Languages } from '../date-picker/date.types';\n\n/**\n * This components displays the list item.\n * This centralizes styles and functionality, and helps reduce redundant code\n * in consumer components such as `limel-list` and `limel-menu-list`.\n *\n * :::note\n * The component has `shadow: false`. There are a few reasons for it:\n * 1. This is to improve performance, and ensure that its internal elements are\n * considered as internal parts of the consumer's DOM.\n * 2. The consumer does not need to implement the interactive styles\n * (such as `visualize-keyboard-focus` mixin) on their own. Since there is no\n * shadow DOM, our mixins can be applied directly to the `limel-list-item` elements,\n * within the component's own styles.\n * 3. Most importantly, the MDCList checks the light DOM of each list item\n * to find native inputs to decide the list mode (checkbox/radio).\n * With `shadow: true`, those inputs would be hidden inside the `limel-list-items`’s\n * shadow DOM, so MDC wouldn’t detect them and therefore throw errors, when given\n * an array index (for the items).\n * With `shadow: false`, the native `<input type=\"checkbox/radio\">` from this template\n * would be visible to MDC.\n * :::\n * @exampleComponent limel-example-list-item-basic\n * @exampleComponent limel-example-list-item-icon\n * @exampleComponent limel-example-list-item-icon-size\n * @exampleComponent limel-example-list-item-pictures\n * @exampleComponent limel-example-list-item-multiple-lines\n * @exampleComponent limel-example-list-item-interactive\n * @exampleComponent limel-example-list-item-radio\n * @exampleComponent limel-example-list-item-checkbox\n * @exampleComponent limel-example-list-item-actions\n * @exampleComponent limel-example-list-item-primary-component\n * @exampleComponent limel-example-list-item-command-text\n * @private\n */\n@Component({\n tag: 'limel-list-item',\n shadow: false,\n styleUrl: 'list-item.scss',\n})\nexport class ListItemComponent implements ListItem {\n /**\n * Defines the language for translations.\n * Will translate the translatable strings on the components.\n */\n @Prop({ reflect: true })\n public language: Languages = 'en';\n\n /**\n * {@inheritdoc ListItem.value}\n */\n @Prop()\n public value?: any;\n\n /**\n * {@inheritdoc ListItem.text}\n */\n @Prop({ reflect: true })\n public text: string;\n\n /**\n * {@inheritdoc ListItem.secondaryText}\n */\n @Prop({ reflect: true })\n public secondaryText?: string;\n\n /**\n * {@inheritdoc ListItem.disabled}\n */\n @Prop({ reflect: true })\n public disabled = false;\n\n /**\n * {@inheritdoc ListItem.icon}\n */\n @Prop()\n public icon?: string | ListItem['icon'];\n\n /**\n * Size of the icon displayed for this item.\n */\n @Prop({ reflect: true })\n public iconSize: IconSize = 'small';\n\n /**\n * Set to `true` if the list should display larger icons with a background\n */\n @Prop({ reflect: true })\n public badgeIcon = false;\n\n /**\n * {@inheritdoc ListItem.selected}\n */\n @Prop({ reflect: true })\n public selected = false;\n\n /**\n * {@inheritdoc ListItem.selected}\n */\n @Prop()\n public actions?: ListItem['actions'];\n\n /**\n * {@inheritdoc ListItem.selected}\n */\n @Prop()\n public primaryComponent?: ListItem['primaryComponent'];\n\n /**\n * {@inheritdoc ListItem.image}\n */\n @Prop()\n public image?: ListItem['image'];\n\n /**\n * The semantic role of the list item. This affects the ARIA role\n * and the interaction behavior.\n *\n * - 'option' → selectable via click/Enter/Space, aria-selected\n * - 'radio'/'checkbox' → selectable, aria-checked\n * - 'menuitem'/'listitem' → activation only, no selection toggle\n */\n @Prop({ reflect: true })\n public type: 'listitem' | 'menuitem' | 'option' | 'radio' | 'checkbox' =\n 'listitem';\n\n /**\n * Used to describe the list item for assistive technology.\n */\n private readonly descriptionId: string;\n\n /**\n * Used to label the list item for assistive technology.\n */\n private readonly labelId: string;\n\n // Memoized reference for the action items to avoid unnecessary updates\n private memoizedActions?: Array<MenuItem | ListSeparator>;\n\n constructor() {\n this.labelId = createRandomString();\n this.descriptionId = createRandomString();\n }\n\n public render() {\n const ariaProps: any = {\n 'aria-labelledby': this.labelId,\n 'aria-describedby': this.secondaryText\n ? this.descriptionId\n : undefined,\n 'aria-disabled': this.disabled ? 'true' : 'false',\n };\n\n // ARIA state depending on `role`/`type`\n if (this.type === 'radio' || this.type === 'checkbox') {\n ariaProps['aria-checked'] = this.selected ? 'true' : 'false';\n } else if (this.type === 'option' || this.type === 'menuitem') {\n // aria-selected for `option` (spec);\n // also keep for `menuitem` for visual state consistency\n ariaProps['aria-selected'] = this.selected ? 'true' : 'false';\n }\n\n return (\n <Host\n role={this.getHostRole()}\n class={{\n 'has-primary-component': !!this.primaryComponent?.name,\n }}\n {...ariaProps}\n >\n {this.renderRadioButton()}\n {this.renderCheckbox()}\n {this.renderIcon()}\n {this.renderImage()}\n {this.renderPrimaryComponent()}\n <div class=\"text\">\n {this.renderLabel()}\n {this.renderDescription()}\n </div>\n {this.renderActionMenu(this.actions)}\n </Host>\n );\n }\n\n private renderLabel = () => {\n return (\n <span class=\"label\" id={this.labelId}>\n {this.text}\n </span>\n );\n };\n\n private renderDescription = () => {\n if (!this.secondaryText) {\n return;\n }\n\n return (\n <span class=\"description\" id={this.descriptionId}>\n {this.secondaryText}\n </span>\n );\n };\n\n private renderIcon = () => {\n const iconName = getIconName(this.icon);\n if (!iconName) {\n return;\n }\n\n let iconColor: string | undefined;\n let iconBackgroundColor: string | undefined;\n let title: string | undefined;\n\n if (typeof this.icon === 'object') {\n iconColor = this.icon.color;\n iconBackgroundColor = this.icon.backgroundColor;\n title = this.icon.title;\n }\n\n const iconProps = {\n 'aria-label': title,\n 'aria-hidden': title ? null : 'true',\n name: iconName,\n style: {\n color: iconColor,\n 'background-color': iconBackgroundColor,\n },\n badge: this.badgeIcon,\n size: this.iconSize,\n };\n\n return <limel-icon {...iconProps} />;\n };\n\n private renderPrimaryComponent = () => {\n const primary = this.primaryComponent;\n if (!primary?.name) {\n return;\n }\n\n const PrimaryComponent: any = primary.name;\n const props = primary.props || {};\n\n return <PrimaryComponent {...props} />;\n };\n\n private renderImage = () => {\n if (!this.image) {\n return;\n }\n\n return <img src={this.image.src} alt={this.image.alt} loading=\"lazy\" />;\n };\n\n private renderActionMenu = (actions: Array<MenuItem | ListSeparator>) => {\n if (!actions || actions.length === 0) {\n return;\n }\n\n const stableActions = this.getStableActions(actions);\n return (\n <limel-menu\n class=\"mdc-deprecated-list-item__meta\"\n items={stableActions}\n openDirection=\"left-start\"\n >\n <limel-icon-button\n class=\"action-menu-trigger\"\n slot=\"trigger\"\n icon=\"menu_2\"\n label={this.actionMenuLabel()}\n />\n </limel-menu>\n );\n };\n\n /**\n * Returns a stable reference for the provided actions array to avoid\n * unnecessary re-renders of the action menu when the reference is unchanged.\n *\n * @param actions The actions (and separators) to display in the menu\n * @returns The same array instance that was previously seen, if unchanged\n */\n private getStableActions(\n actions: Array<MenuItem | ListSeparator>\n ): Array<MenuItem | ListSeparator> {\n if (this.memoizedActions === actions) {\n return this.memoizedActions;\n }\n this.memoizedActions = actions;\n return actions;\n }\n\n private renderRadioButton = () => {\n if (this.type !== 'radio') {\n return;\n }\n\n return (\n <RadioButtonTemplate\n id={`radio_${this.labelId}`}\n checked={this.selected}\n disabled={this.disabled}\n />\n );\n };\n\n private renderCheckbox = () => {\n if (this.type !== 'checkbox') {\n return;\n }\n\n return (\n <CheckboxTemplate\n id={`checkbox_${this.labelId}`}\n checked={this.selected}\n disabled={this.disabled}\n />\n );\n };\n\n private getHostRole(): string {\n switch (this.type) {\n case 'option': {\n return 'option';\n }\n case 'radio': {\n return 'radio';\n }\n case 'checkbox': {\n return 'checkbox';\n }\n case 'menuitem': {\n return 'menuitem';\n }\n default: {\n return 'listitem';\n }\n }\n }\n\n private actionMenuLabel = (): string => {\n return translate.get('file-viewer.more-actions', this.language);\n };\n}\n"],"version":3}
@@ -26192,9 +26192,14 @@ const getLinkDataAtPosition = (view, event) => {
26192
26192
  return { href: href, text: text, from: from, to: to };
26193
26193
  };
26194
26194
  const processModClickEvent = (view, event) => {
26195
- const { href } = getLinkDataAtPosition(view, event);
26195
+ const linkData = getLinkDataAtPosition(view, event);
26196
+ if (!linkData.href) {
26197
+ return false;
26198
+ }
26199
+ event.preventDefault();
26200
+ const { href } = linkData;
26196
26201
  if (href) {
26197
- window.open(href, '_blank');
26202
+ window.open(href, '_blank', 'noopener,noreferrer');
26198
26203
  return true;
26199
26204
  }
26200
26205
  return false;
@@ -26207,32 +26212,21 @@ const openLinkMenu = (view, href, text) => {
26207
26212
  });
26208
26213
  view.dom.dispatchEvent(event);
26209
26214
  };
26210
- let lastClickTime = 0;
26211
- const DOUBLE_CLICK_DELAY = 200;
26212
- let clickTimeout;
26213
- const processClickEvent = (view, event) => {
26214
- const now = Date.now();
26215
- if (now - lastClickTime < DOUBLE_CLICK_DELAY) {
26216
- clearTimeout(clickTimeout);
26217
- lastClickTime = now; // Reset lastClickTime to prevent single-click action
26215
+ const processDoubleClickEvent = (view, event) => {
26216
+ const linkData = getLinkDataAtPosition(view, event);
26217
+ if (!linkData) {
26218
26218
  return false;
26219
26219
  }
26220
- lastClickTime = now;
26221
- clickTimeout = setTimeout(() => {
26222
- const linkData = getLinkDataAtPosition(view, event);
26223
- if (linkData) {
26224
- const { href, text, from, to } = linkData;
26225
- const transaction = view.state.tr.setSelection(TextSelection.create(view.state.doc, from, to));
26226
- view.dispatch(transaction);
26227
- openLinkMenu(view, href, text);
26228
- }
26229
- }, DOUBLE_CLICK_DELAY);
26220
+ const { href, text, from, to } = linkData;
26221
+ const transaction = view.state.tr.setSelection(TextSelection.create(view.state.doc, from, to));
26222
+ view.dispatch(transaction);
26223
+ openLinkMenu(view, href, text);
26230
26224
  return true;
26231
26225
  };
26232
26226
  /**
26233
- * Regular expression for matching URLs, mailto links, and phone links
26227
+ * Regular expression for matching URLs, mailto links, phone links, and bare www-links
26234
26228
  */
26235
- const URL_REGEX = /(https?:\/\/[^\s<>"']+|mailto:[^\s<>"']+|tel:[^\s<>"']+)/g;
26229
+ const URL_REGEX = /(https?:\/\/[^\s<>"']+|mailto:[^\s<>"']+|tel:[^\s<>"']+|www\.[^\s<>"']+)/g;
26236
26230
  /**
26237
26231
  * Checks if the text contains any URLs, mailto links, or phone links
26238
26232
  * @param text
@@ -26256,8 +26250,19 @@ const createTextNode = (schema, content) => {
26256
26250
  * @param url
26257
26251
  */
26258
26252
  const createLinkNode = (schema, url) => {
26259
- const linkMark = schema.marks.link.create(markdownParser.getLinkAttributes(url, url));
26260
- return schema.text(url, [linkMark]);
26253
+ const normalizeUrlForLinkMark = (input) => {
26254
+ let output = input.trim();
26255
+ while (output.endsWith('\\')) {
26256
+ output = output.slice(0, -1);
26257
+ }
26258
+ if (output.toLowerCase().startsWith('www.')) {
26259
+ output = `https://${output}`;
26260
+ }
26261
+ return output;
26262
+ };
26263
+ const normalizedUrl = normalizeUrlForLinkMark(url);
26264
+ const linkMark = schema.marks.link.create(markdownParser.getLinkAttributes(normalizedUrl, normalizedUrl));
26265
+ return schema.text(normalizedUrl, [linkMark]);
26261
26266
  };
26262
26267
  /**
26263
26268
  * Finds all link matches in the provided text
@@ -26277,6 +26282,36 @@ const findLinkMatches = (text) => {
26277
26282
  }
26278
26283
  return matches;
26279
26284
  };
26285
+ /**
26286
+ * Creates nodes for the pasted text while preserving soft line breaks.
26287
+ * - Each newline becomes a `hard_break`.
26288
+ * - Empty lines are preserved (consecutive newlines => multiple `hard_break`s).
26289
+ * - URLs inside each line are converted to link-marked text.
26290
+ * @param text - Raw pasted text
26291
+ * @param schema - ProseMirror schema
26292
+ */
26293
+ const createNodesWithLinksAndBreaks = (text, schema) => {
26294
+ // Split preserves empty lines between consecutive newlines
26295
+ const lines = text.split(/\r\n|\r|\n/);
26296
+ const nodes = [];
26297
+ for (const [index, line] of lines.entries()) {
26298
+ if (line.length > 0) {
26299
+ nodes.push(...createNodesWithLinks(line, schema));
26300
+ }
26301
+ if (index < lines.length - 1) {
26302
+ const hb = schema.nodes.hard_break;
26303
+ if (hb) {
26304
+ nodes.push(hb.create());
26305
+ }
26306
+ else {
26307
+ // Fallback: if schema lacks hard_break, defer to default paste behavior
26308
+ // (Do NOT throw; keep behavior stable across versions)
26309
+ console.warn('hard_break node not found in schema');
26310
+ }
26311
+ }
26312
+ }
26313
+ return nodes;
26314
+ };
26280
26315
  /**
26281
26316
  * Creates text nodes with links for any URLs, mailto links, or phone links found in the text
26282
26317
  * @param text
@@ -26378,7 +26413,8 @@ const processPasteEvent$1 = (view, event) => {
26378
26413
  if (!text || !hasUrls(text)) {
26379
26414
  return false;
26380
26415
  }
26381
- const nodes = createNodesWithLinks(text, view.state.schema);
26416
+ const nodes = createNodesWithLinksAndBreaks(text, view.state.schema);
26417
+ event.preventDefault();
26382
26418
  pasteAsLink(view, nodes);
26383
26419
  return true;
26384
26420
  };
@@ -26395,11 +26431,12 @@ const createLinkPlugin = (updateLinkCallback) => {
26395
26431
  event.button === 0) {
26396
26432
  return processModClickEvent(view, event);
26397
26433
  }
26434
+ },
26435
+ dblclick: (view, event) => {
26398
26436
  if (event.button !== MouseButtons.Right) {
26399
26437
  // We want to ignore right-clicks
26400
- return processClickEvent(view, event);
26438
+ return processDoubleClickEvent(view, event);
26401
26439
  }
26402
- return true;
26403
26440
  },
26404
26441
  click: (_view, event) => {
26405
26442
  if (!(event.target instanceof HTMLElement)) {