@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 +20 -0
- package/README.md +10 -1
- package/dist/cjs/limel-list-item.cjs.entry.js +1 -86
- package/dist/cjs/limel-list-item.cjs.entry.js.map +1 -1
- package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +64 -27
- package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js.map +1 -1
- package/dist/collection/components/list-item/list-item.js +2 -109
- package/dist/collection/components/list-item/list-item.js.map +1 -1
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/link-plugin.js +64 -27
- package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link/link-plugin.js.map +1 -1
- package/dist/esm/limel-list-item.entry.js +2 -87
- package/dist/esm/limel-list-item.entry.js.map +1 -1
- package/dist/esm/limel-prosemirror-adapter.entry.js +64 -27
- package/dist/esm/limel-prosemirror-adapter.entry.js.map +1 -1
- package/dist/lime-elements/lime-elements.esm.js +1 -1
- package/dist/lime-elements/p-048c0d8e.entry.js +2 -0
- package/dist/lime-elements/p-048c0d8e.entry.js.map +1 -0
- package/dist/lime-elements/{p-202107e9.entry.js → p-6c60172e.entry.js} +2 -2
- package/dist/lime-elements/p-6c60172e.entry.js.map +1 -0
- package/dist/types/components/list-item/list-item.d.ts +0 -13
- package/dist/types/components.d.ts +0 -11
- package/package.json +1 -1
- package/dist/lime-elements/p-0334e593.entry.js +0 -2
- package/dist/lime-elements/p-0334e593.entry.js.map +0 -1
- package/dist/lime-elements/p-202107e9.entry.js.map +0 -1
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
|
[](https://www.npmjs.com/package/@limetech/lime-elements) [](https://github.com/semantic-release/semantic-release) [](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
|
-
- 🆕 **
|
|
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
|
|
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":";;;;;;;;;;AAsCO,MAAM,mBAAmB,GAE5B,CAAC,KAAK;EACN,QACIA,iBACI,KAAK,EAAE;MACH,eAAe,EAAE,IAAI;MACrB,cAAc,EAAE,IAAI;MACpB,OAAO,EAAE,KAAK,CAAC,OAAO;MACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;KAC3B;IAEDA,mBACI,IAAI,EAAC,OAAO,EACZ,EAAE,EAAE,KAAK,CAAC,EAAE,EACZ,OAAO,EAAE,KAAK,CAAC,OAAO,EACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAC1B;IACFA,iBAAK,KAAK,EAAC,KAAK,GAAG;IACnBA,mBAAO,KAAK,EAAC,qBAAqB,EAAC,OAAO,EAAE,KAAK,CAAC,EAAE,IAC/C,KAAK,CAAC,KAAK,CACR,CACN,EACR;AACN,CAAC;;AC/DD,MAAM,WAAW,GAAG,y1QAAy1Q;;MCmDh2Q,iBAAiB;EAmG1B;;IA6CQ,gBAAW,GAAG;MAClB,QACIA,kBAAM,KAAK,EAAC,OAAO,EAAC,EAAE,EAAE,IAAI,CAAC,OAAO,IAC/B,IAAI,CAAC,IAAI,CACP,EACT;KACL,CAAC;IAEM,sBAAiB,GAAG;MACxB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;QACrB,OAAO;OACV;MAED,QACIA,kBAAM,KAAK,EAAC,aAAa,EAAC,EAAE,EAAE,IAAI,CAAC,aAAa,IAC3C,IAAI,CAAC,aAAa,CAChB,EACT;KACL,CAAC;IAEM,eAAU,GAAG;MACjB,MAAM,QAAQ,GAAGC,wBAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;MACxC,IAAI,CAAC,QAAQ,EAAE;QACX,OAAO;OACV;MAED,IAAI,SAA6B,CAAC;MAClC,IAAI,mBAAuC,CAAC;MAC5C,IAAI,KAAyB,CAAC;MAE9B,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE;QAC/B,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;QAC5B,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;QAChD,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;OAC3B;MAED,MAAM,SAAS,GAAG;QACd,YAAY,EAAE,KAAK;QACnB,aAAa,EAAE,KAAK,GAAG,IAAI,GAAG,MAAM;QACpC,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE;UACH,KAAK,EAAE,SAAS;UAChB,kBAAkB,EAAE,mBAAmB;SAC1C;QACD,KAAK,EAAE,IAAI,CAAC,SAAS;QACrB,IAAI,EAAE,IAAI,CAAC,QAAQ;OACtB,CAAC;MAEF,OAAOD,wCAAgB,SAAS,EAAI,CAAC;KACxC,CAAC;IAEM,2BAAsB,GAAG;MAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC;MACtC,IAAI,EAAC,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,IAAI,CAAA,EAAE;QAChB,OAAO;OACV;MAED,MAAM,gBAAgB,GAAQ,OAAO,CAAC,IAAI,CAAC;MAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;MAElC,OAAOA,QAAC,gBAAgB,oBAAK,KAAK,EAAI,CAAC;KAC1C,CAAC;IAEM,gBAAW,GAAG;MAClB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;QACb,OAAO;OACV;MAED,OAAOA,iBAAK,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAC,MAAM,GAAG,CAAC;KAC3E,CAAC;IAEM,qBAAgB,GAAG,CAAC,OAAwC;MAChE,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;QAClC,OAAO;OACV;MAED,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;MACrD,QACIA,wBACI,KAAK,EAAC,gCAAgC,EACtC,KAAK,EAAE,aAAa,EACpB,aAAa,EAAC,YAAY,IAE1BA,+BACI,KAAK,EAAC,qBAAqB,EAC3B,IAAI,EAAC,SAAS,EACd,IAAI,EAAC,QAAQ,EACb,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,GAC/B,CACO,EACf;KACL,CAAC;IAmBM,sBAAiB,GAAG;MACxB,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE;QACvB,OAAO;OACV;MAED,QACIA,QAAC,mBAAmB,IAChB,EAAE,EAAE,SAAS,IAAI,CAAC,OAAO,EAAE,EAC3B,OAAO,EAAE,IAAI,CAAC,QAAQ,EACtB,QAAQ,EAAE,IAAI,CAAC,QAAQ,GACzB,EACJ;KACL,CAAC;IAEM,mBAAc,GAAG;MACrB,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE;QAC1B,OAAO;OACV;MAED,QACIA,QAACE,kCAAgB,IACb,EAAE,EAAE,YAAY,IAAI,CAAC,OAAO,EAAE,EAC9B,OAAO,EAAE,IAAI,CAAC,QAAQ,EACtB,QAAQ,EAAE,IAAI,CAAC,QAAQ,GACzB,EACJ;KACL,CAAC;IAsBM,oBAAe,GAAG;MACtB,OAAOC,sBAAS,CAAC,GAAG,CAAC,0BAA0B,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;KACnE,CAAC;oBA1S2B,IAAI;;;;oBAwBf,KAAK;;oBAYK,OAAO;qBAMhB,KAAK;oBAMN,KAAK;;;;gBA8BnB,UAAU;IAgBV,IAAI,CAAC,OAAO,GAAGC,+BAAkB,EAAE,CAAC;IACpC,IAAI,CAAC,aAAa,GAAGA,+BAAkB,EAAE,CAAC;GAC7C;EAEM,MAAM;;IACT,MAAM,SAAS,GAAQ;MACnB,iBAAiB,EAAE,IAAI,CAAC,OAAO;MAC/B,kBAAkB,EAAE,IAAI,CAAC,aAAa;UAChC,IAAI,CAAC,aAAa;UAClB,SAAS;MACf,eAAe,EAAE,IAAI,CAAC,QAAQ,GAAG,MAAM,GAAG,OAAO;KACpD,CAAC;;IAGF,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE;MACnD,SAAS,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;KAChE;SAAM,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE;;;MAG3D,SAAS,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;KACjE;IAED,QACIJ,QAACK,UAAI,kBACD,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,EACxB,KAAK,EAAE;QACH,uBAAuB,EAAE,CAAC,EAAC,MAAA,IAAI,CAAC,gBAAgB,0CAAE,IAAI,CAAA;OACzD,IACG,SAAS,GAEZ,IAAI,CAAC,iBAAiB,EAAE,EACxB,IAAI,CAAC,cAAc,EAAE,EACrB,IAAI,CAAC,UAAU,EAAE,EACjB,IAAI,CAAC,WAAW,EAAE,EAClB,IAAI,CAAC,sBAAsB,EAAE,EAC9BL,iBAAK,KAAK,EAAC,MAAM,IACZ,IAAI,CAAC,WAAW,EAAE,EAClB,IAAI,CAAC,iBAAiB,EAAE,CACvB,EACL,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CACjC,EACT;GACL;;;;;;;;EAsGO,gBAAgB,CACpB,OAAwC;IAExC,IAAI,IAAI,CAAC,eAAe,KAAK,OAAO,EAAE;MAClC,OAAO,IAAI,CAAC,eAAe,CAAC;KAC/B;IACD,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC;IAC/B,OAAO,OAAO,CAAC;GAClB;EA8BO,WAAW;IACf,QAAQ,IAAI,CAAC,IAAI;MACb,KAAK,QAAQ,EAAE;QACX,OAAO,QAAQ,CAAC;OACnB;MACD,KAAK,OAAO,EAAE;QACV,OAAO,OAAO,CAAC;OAClB;MACD,KAAK,UAAU,EAAE;QACb,OAAO,UAAU,CAAC;OACrB;MACD,KAAK,UAAU,EAAE;QACb,OAAO,UAAU,CAAC;OACrB;MACD,SAAS;QACL,OAAO,UAAU,CAAC;OACrB;KACJ;GACJ;;;;;;","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
|
|
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
|
-
|
|
26211
|
-
const
|
|
26212
|
-
|
|
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
|
-
|
|
26221
|
-
|
|
26222
|
-
|
|
26223
|
-
|
|
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
|
|
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
|
|
26260
|
-
|
|
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 =
|
|
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
|
|
26438
|
+
return processDoubleClickEvent(view, event);
|
|
26401
26439
|
}
|
|
26402
|
-
return true;
|
|
26403
26440
|
},
|
|
26404
26441
|
click: (_view, event) => {
|
|
26405
26442
|
if (!(event.target instanceof HTMLElement)) {
|