@limetech/lime-elements 38.11.0 → 38.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/index.cjs.js +0 -9
  3. package/dist/cjs/index.cjs.js.map +1 -1
  4. package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +209 -111
  5. package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js.map +1 -1
  6. package/dist/cjs/limel-snackbar.cjs.entry.js.map +1 -1
  7. package/dist/cjs/limel-text-editor.cjs.entry.js +7 -1
  8. package/dist/cjs/limel-text-editor.cjs.entry.js.map +1 -1
  9. package/dist/collection/components/snackbar/snackbar.js +1 -1
  10. package/dist/collection/components/snackbar/snackbar.js.map +1 -1
  11. package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-items.js.map +1 -1
  12. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/inserter.js +15 -54
  13. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/inserter.js.map +1 -1
  14. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/node.js +52 -44
  15. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/node.js.map +1 -1
  16. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/view.js +11 -13
  17. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/image/view.js.map +1 -1
  18. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/link-plugin.js.map +1 -1
  19. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/append-transaction-handler.js.map +1 -1
  20. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/detect-trigger-removal.js.map +1 -1
  21. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/get-trigger-event-detail.js.map +1 -1
  22. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/monitor-triggered-text.js.map +1 -1
  23. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/send-trigger-event.js.map +1 -1
  24. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/text-input-handler.js.map +1 -1
  25. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/factory.js.map +1 -1
  26. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/trigger/inserter.js.map +1 -1
  27. package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js +54 -8
  28. package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js.map +1 -1
  29. package/dist/collection/components/text-editor/text-editor.js +38 -4
  30. package/dist/collection/components/text-editor/text-editor.js.map +1 -1
  31. package/dist/collection/components/text-editor/text-editor.types.js +1 -9
  32. package/dist/collection/components/text-editor/text-editor.types.js.map +1 -1
  33. package/dist/collection/components/text-editor/utils/metadata-utils.js +108 -0
  34. package/dist/collection/components/text-editor/utils/metadata-utils.js.map +1 -0
  35. package/dist/esm/index.js +0 -2
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/limel-prosemirror-adapter.entry.js +209 -111
  38. package/dist/esm/limel-prosemirror-adapter.entry.js.map +1 -1
  39. package/dist/esm/limel-snackbar.entry.js.map +1 -1
  40. package/dist/esm/limel-text-editor.entry.js +7 -1
  41. package/dist/esm/limel-text-editor.entry.js.map +1 -1
  42. package/dist/lime-elements/index.esm.js +1 -1
  43. package/dist/lime-elements/index.esm.js.map +1 -1
  44. package/dist/lime-elements/lime-elements.esm.js +1 -1
  45. package/dist/lime-elements/p-3a87b175.entry.js.map +1 -1
  46. package/dist/lime-elements/p-7b039dab.entry.js +2 -0
  47. package/dist/lime-elements/p-7b039dab.entry.js.map +1 -0
  48. package/dist/lime-elements/{p-033fa919.entry.js → p-7f3045bd.entry.js} +2 -2
  49. package/dist/lime-elements/p-7f3045bd.entry.js.map +1 -0
  50. package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-items.d.ts +2 -2
  51. package/dist/types/components/text-editor/prosemirror-adapter/plugins/image/inserter.d.ts +2 -7
  52. package/dist/types/components/text-editor/prosemirror-adapter/plugins/image/node.d.ts +9 -0
  53. package/dist/types/components/text-editor/prosemirror-adapter/plugins/link-plugin.d.ts +0 -4
  54. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/append-transaction-handler.d.ts +1 -1
  55. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/detect-trigger-removal.d.ts +1 -1
  56. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/get-trigger-event-detail.d.ts +2 -2
  57. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/monitor-triggered-text.d.ts +2 -2
  58. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/send-trigger-event.d.ts +1 -1
  59. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory-helpers/text-input-handler.d.ts +1 -1
  60. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/factory.d.ts +1 -1
  61. package/dist/types/components/text-editor/prosemirror-adapter/plugins/trigger/inserter.d.ts +1 -1
  62. package/dist/types/components/text-editor/prosemirror-adapter/prosemirror-adapter.d.ts +10 -0
  63. package/dist/types/components/text-editor/text-editor.d.ts +10 -0
  64. package/dist/types/components/text-editor/text-editor.types.d.ts +32 -7
  65. package/dist/types/components/text-editor/utils/metadata-utils.d.ts +22 -0
  66. package/dist/types/components.d.ts +17 -4
  67. package/package.json +1 -1
  68. package/dist/cjs/text-editor.types-5e5567e2.js +0 -13
  69. package/dist/cjs/text-editor.types-5e5567e2.js.map +0 -1
  70. package/dist/esm/text-editor.types-e82469d1.js +0 -13
  71. package/dist/esm/text-editor.types-e82469d1.js.map +0 -1
  72. package/dist/lime-elements/p-033fa919.entry.js.map +0 -1
  73. package/dist/lime-elements/p-7006fafe.entry.js +0 -2
  74. package/dist/lime-elements/p-7006fafe.entry.js.map +0 -1
  75. package/dist/lime-elements/p-9ca516ed.js +0 -2
  76. package/dist/lime-elements/p-9ca516ed.js.map +0 -1
@@ -1 +1 @@
1
- {"file":"index.js","mappings":";;AAwSA;;;;IAIY;AAAZ,WAAY,cAAc;;;;EAItB,qCAAmB,CAAA;;;;EAKnB,+BAAa,CAAA;;;;;;;;EASb,6BAAW,CAAA;AACf,CAAC,EAnBW,cAAc,KAAd,cAAc;;ACvJ1B;;;;IAIY;AAAZ,WAAY,oBAAoB;;;;EAI5B,uCAAe,CAAA;;;;EAKf,uCAAe,CAAA;;;;EAKf,uCAAe,CAAA;;;;EAKf,mCAAW,CAAA;;;;EAKX,uCAAe,CAAA;AACnB,CAAC,EAzBW,oBAAoB,KAApB,oBAAoB;;;;","names":[],"sources":["./src/components/form/form.types.ts","./src/components/table/table.types.ts"],"sourcesContent":["import { JSONSchema7 } from 'json-schema';\nimport { Help } from '../help/help.types';\nimport { EventEmitter } from '@stencil/core';\n\n/**\n * EventEmitter from `@stencil/core`.\n *\n * @public\n */\nexport { EventEmitter } from '@stencil/core';\n\ndeclare module 'json-schema' {\n interface JSONSchema7 {\n /**\n * @internal\n * Unique identifier for the schema\n */\n id?: string;\n\n /**\n * Lime elements specific options that can be specified in a schema\n */\n lime?: Omit<LimeSchemaOptions, 'layout'> & {\n layout?: Partial<LimeLayoutOptions>;\n };\n }\n}\n\n/**\n * @public\n */\nexport interface ValidationStatus {\n /**\n * True if the form is valid, false otherwise\n *\n * If the form is invalid, any errors can be found on the `errors` property\n */\n valid: boolean;\n\n /**\n * List of validation errors\n */\n errors?: FormError[];\n}\n\n/**\n * @public\n */\nexport interface FormError {\n /**\n * Name of the error\n */\n name: string;\n\n /**\n * Params of the error\n */\n params?: unknown;\n\n /**\n * Name of the invalid property\n */\n property: string;\n\n /**\n * Path to the property within the schema\n */\n schemaPath: string;\n\n /**\n * String describing the error\n */\n message: string;\n}\n\n/**\n * @public\n */\nexport type ValidationError = {\n /**\n * Name of the field the error belongs to\n */\n [key: string]: string[] | ValidationError;\n};\n\n/**\n * @public\n */\nexport interface FormComponent<T = any> {\n /**\n * The value of the current property\n */\n value: T;\n\n /**\n * Whether or not the current property is required\n */\n required?: boolean;\n\n /**\n * Whether or not the current property is readonly\n */\n readonly?: boolean;\n\n /**\n * Whether or not the current property is disabled\n */\n disabled?: boolean;\n\n /**\n * The label of the current property\n */\n label?: string;\n\n /**\n * The helper text for the current property\n */\n helperText?: string;\n\n /**\n * Additional contextual information about the form\n */\n formInfo?: FormInfo;\n\n /**\n * The event to emit when the value of the current property has changed\n */\n change: EventEmitter<T>;\n}\n\n/**\n * @public\n */\nexport interface FormInfo {\n /**\n * The schema of the current property\n */\n schema?: FormSchema;\n\n /**\n * The schema of the whole form\n */\n rootSchema?: FormSchema;\n\n /**\n * A tree of errors for this property and its children\n */\n errorSchema?: object;\n\n /**\n * The value of the whole form\n */\n rootValue?: any;\n\n /**\n * The name of the current property\n */\n name?: string;\n\n /**\n * Path to the property within the schema\n */\n schemaPath?: string[];\n}\n\n/**\n * Lime elements specific options that can be specified under the `lime` key in\n * a schema, e.g.\n *\n * ```ts\n * const schema = {\n * type: 'object',\n * lime: {\n * collapsible: true,\n * },\n * };\n * ```\n *\n * @public\n */\nexport interface LimeSchemaOptions {\n /**\n * When specified on an object it will render all sub components inside a\n * collapsible section\n */\n collapsible?: boolean;\n\n /**\n * When `collapsible` is `true`, set this to `false` to make the\n * collapsible section load in the open state.\n * Defaults to `true`.\n */\n collapsed?: boolean;\n\n /**\n * Will render the field using the specified component. The component\n * should implement the `FormComponent` interface\n */\n component?: FormComponentOptions;\n\n /**\n * When specified on an object it will render the sub components with the\n * specified layout\n */\n layout?: LimeLayoutOptions;\n\n /**\n * Mark the field as disabled\n */\n disabled?: boolean;\n\n help?: string | Partial<Help>;\n}\n\n/**\n * Options for a layout to be used in a form\n * @public\n */\nexport type LimeLayoutOptions = GridLayoutOptions & RowLayoutOptions;\n\n/**\n * Options for a component to be rendered inside a form\n *\n * @public\n */\nexport interface FormComponentOptions {\n /**\n * Name of the component\n */\n name?: string;\n\n /**\n * Extra properties to give the component in addition to the properties\n * specified on the `FormComponent` interface\n */\n props?: Record<string, any>;\n}\n\n/**\n * @public\n */\nexport interface FormLayoutOptions<\n T extends FormLayoutType | `${FormLayoutType}` = FormLayoutType.Default,\n> {\n /**\n * The type of layout to use\n */\n type: T;\n}\n\n/**\n * Layout options for a grid layout\n * @public\n */\nexport interface GridLayoutOptions\n extends FormLayoutOptions<FormLayoutType | `${FormLayoutType}`> {\n /**\n * When specified on a component within the grid, the component will take\n * up the the specified number of columns in the form\n */\n // eslint-disable-next-line no-magic-numbers\n colSpan?: 1 | 2 | 3 | 4 | 5 | 'all';\n\n /**\n * When specified on a component within the grid, the component will take\n * up the the specified number of rows in the form\n */\n rowSpan?: number;\n\n /**\n * Number of columns to use in the layout\n */\n // eslint-disable-next-line no-magic-numbers\n columns?: 1 | 2 | 3 | 4 | 5;\n\n /**\n * Attempts to fill in holes earlier in the grid, if smaller items come up\n * later. This may cause items to appear out-of-order, when doing so would\n * fill holes left by larger items. Defaults to `true`.\n */\n dense?: boolean;\n}\n\n/**\n * Layout options for a row layout\n * @public\n */\nexport interface RowLayoutOptions\n extends FormLayoutOptions<FormLayoutType | `${FormLayoutType}`> {\n /**\n * When specified on a field, the chosen icon will be displayed\n * on the left side of the row, beside the title.\n */\n icon?: string;\n}\n\n/**\n * Represents the layout types for a form.\n * @public\n */\nexport enum FormLayoutType {\n /**\n * The default layout\n */\n Default = 'default',\n\n /**\n * Render the form fields using a responsive grid layout\n */\n Grid = 'grid',\n\n /**\n * Render the form fields in full-width rows.\n * Each row can have a leading `icon`, and a field.\n * `title` and `description` provided by the schema will be placed\n * on the row itself, and not on the field.\n * This layout is good for creating UIs for user settings pages.\n */\n Row = 'row',\n}\n\n/**\n * Represents the JSON schema with Lime specific options\n * @public\n */\nexport interface FormSchema<T extends Record<string, any> = any>\n extends JSONSchema7 {\n /**\n * The value of \"items\" MUST be either a valid JSON Schema or an array\n * of valid JSON Schemas.\n *\n * This keyword determines how child instances validate for arrays, and\n * does not directly validate the immediate instance itself.\n *\n * If \"items\" is a schema, validation succeeds if all elements in the\n * array successfully validate against that schema.\n *\n * If \"items\" is an array of schemas, validation succeeds if each\n * element of the instance validates against the schema at the same\n * position, if any.\n *\n * Omitting this keyword has the same behavior as an empty schema.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.4.1\n */\n items?: FormSchemaArrayItem<T> | Array<FormSchemaArrayItem<T>>;\n\n /**\n * The value of \"items\" MUST be either a valid JSON Schema or an array\n * of valid JSON Schemas.\n *\n * This keyword determines how child instances validate for arrays, and\n * does not directly validate the immediate instance itself.\n *\n * If \"items\" is a schema, validation succeeds if all elements in the\n * array successfully validate against that schema.\n *\n * If \"items\" is an array of schemas, validation succeeds if each\n * element of the instance validates against the schema at the same\n * position, if any.\n *\n * Omitting this keyword has the same behavior as an empty schema.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.4.2\n */\n additionalItems?: FormSchemaArrayItem<T>;\n\n /**\n * The value of this keyword MUST be a valid JSON Schema.\n *\n * An array instance is valid against \"contains\" if at least one of its\n * elements is valid against the given schema.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.4.6\n */\n contains?: FormSchemaArrayItem<T>;\n\n /**\n * The value of this keyword MUST be an array. Elements of this array,\n * if any, MUST be strings, and MUST be unique.\n *\n * An object instance is valid against this keyword if every item in the\n * array is the name of a property in the instance.\n *\n * Omitting this keyword has the same behavior as an empty array.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.3\n */\n required?: Array<ReplaceObjectType<T, Extract<keyof T, string>, string>>;\n\n /**\n * The value of \"properties\" MUST be an object. Each value of this\n * object MUST be a valid JSON Schema.\n *\n * This keyword determines how child instances validate for objects, and\n * does not directly validate the immediate instance itself.\n *\n * Validation succeeds if, for each name that appears in both the\n * instance and as a name within this keyword's value, the child\n * instance for that name successfully validates against the\n * corresponding schema.\n *\n * Omitting this keyword has the same behavior as an empty object.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.4\n */\n properties?: ReplaceObjectType<\n T,\n FormSubKeySchema<T>,\n Record<string, FormSchema>\n >;\n\n /**\n * This keyword's value MUST be a non-empty array. Each item of the\n * array MUST be a valid JSON Schema.\n *\n * An instance validates successfully against this keyword if it\n * validates successfully against all schemas defined by this keyword's\n * value.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.7.1\n */\n allOf?: Array<FormSchemaArrayItem<T>>;\n\n /**\n * This keyword's value MUST be a non-empty array. Each item of the\n * array MUST be a valid JSON Schema.\n *\n * An instance validates successfully against this keyword if it\n * validates successfully against at least one schema defined by this\n * keyword's value.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.7.2\n */\n anyOf?: Array<FormSchemaArrayItem<T>>;\n\n /**\n * This keyword's value MUST be a non-empty array. Each item of the\n * array MUST be a valid JSON Schema.\n *\n * An instance validates successfully against this keyword if it\n * validates successfully against exactly one schema defined by this\n * keyword's value.\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.7.3\n */\n oneOf?: Array<FormSchemaArrayItem<T>>;\n\n /**\n * The value of \"patternProperties\" MUST be an object. Each property\n * name of this object SHOULD be a valid regular expression, according\n * to the ECMA 262 regular expression dialect. Each property value of\n * this object MUST be a valid JSON Schema.\n *\n * This keyword determines how child instances validate for objects, and\n * does not directly validate the immediate instance itself. Validation\n * of the primitive instance type against this keyword always succeeds.\n *\n * Validation succeeds if, for each instance name that matches any\n * regular expressions that appear as a property name in this keyword's\n * value, the child instance for that name successfully validates\n * against each schema that corresponds to a matching regular\n * expression.\n *\n * Omitting this keyword has the same behavior as an empty object.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.5\n */\n patternProperties?: Record<string, FormSchema>;\n\n /**\n * The value of \"additionalProperties\" MUST be a valid JSON Schema.\n *\n * This keyword determines how child instances validate for objects, and\n * does not directly validate the immediate instance itself.\n *\n * Validation with \"additionalProperties\" applies only to the child\n * values of instance names that do not match any names in \"properties\",\n * and do not match any regular expression in \"patternProperties\".\n *\n * For all such properties, validation succeeds if the child instance\n * validates against the \"additionalProperties\" schema.\n *\n * Omitting this keyword has the same behavior as an empty schema.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.6\n */\n additionalProperties?: FormSchema | boolean;\n\n /**\n * This keyword specifies rules that are evaluated if the instance is an\n * object and contains a certain property.\n *\n * This keyword's value MUST be an object. Each property specifies a\n * dependency. Each dependency value MUST be an array or a valid JSON\n * Schema.\n *\n * If the dependency value is a subschema, and the dependency key is a\n * property in the instance, the entire instance must validate against\n * the dependency value.\n *\n * If the dependency value is an array, each element in the array, if\n * any, MUST be a string, and MUST be unique. If the dependency key is\n * a property in the instance, each of the items in the dependency value\n * must be a property that exists in the instance.\n *\n * Omitting this keyword has the same behavior as an empty object.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.7\n */\n dependencies?: Record<string, FormSchema | string[]>;\n\n /**\n * The value of \"propertyNames\" MUST be a valid JSON Schema.\n *\n * If the instance is an object, this keyword validates if every\n * property name in the instance validates against the provided schema.\n * Note the property name that the schema is testing will always be a\n * string.\n *\n * Omitting this keyword has the same behavior as an empty schema.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.8\n */\n propertyNames?: FormSchema;\n\n /**\n * This keyword's value MUST be a valid JSON Schema.\n *\n * This validation outcome of this keyword's subschema has no direct\n * effect on the overall validation result. Rather, it controls which\n * of the \"then\" or \"else\" keywords are evaluated.\n *\n * Instances that successfully validate against this keyword's subschema\n * MUST also be valid against the subschema value of the \"then\" keyword,\n * if present.\n *\n * Instances that fail to validate against this keyword's subschema MUST\n * also be valid against the subschema value of the \"else\" keyword, if\n * present.\n *\n * If annotations (Section 3.3) are being collected, they are collected\n * from this keyword's subschema in the usual way, including when the\n * keyword is present without either \"then\" or \"else\".\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.6.1\n */\n if?: FormSchema;\n\n /**\n * This keyword's value MUST be a valid JSON Schema.\n *\n * This validation outcome of this keyword's subschema has no direct\n * effect on the overall validation result. Rather, it controls which\n * of the \"then\" or \"else\" keywords are evaluated.\n *\n * Instances that successfully validate against this keyword's subschema\n * MUST also be valid against the subschema value of the \"then\" keyword,\n * if present.\n *\n * Instances that fail to validate against this keyword's subschema MUST\n * also be valid against the subschema value of the \"else\" keyword, if\n * present.\n *\n * If annotations (Section 3.3) are being collected, they are collected\n * from this keyword's subschema in the usual way, including when the\n * keyword is present without either \"then\" or \"else\".\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.6.2\n */\n then?: FormSchema;\n\n /**\n * This keyword's value MUST be a valid JSON Schema.\n *\n * When \"if\" is present, and the instance fails to validate against its\n * subschema, then valiation succeeds against this keyword if the\n * instance successfully validates against this keyword's subschema.\n *\n * This keyword has no effect when \"if\" is absent, or when the instance\n * successfully validates against its subschema. Implementations MUST\n * NOT evaluate the instance against this keyword, for either validation\n * or annotation collection purposes, in such cases.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.6.3\n */\n else?: FormSchema;\n\n /**\n * This keyword's value MUST be a valid JSON Schema.\n *\n * An instance is valid against this keyword if it fails to validate\n * successfully against the schema defined by this keyword.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.7.4\n */\n not?: FormSchema;\n\n /**\n * The \"$defs\" keywords provides a standardized location for\n * schema authors to inline re-usable JSON Schemas into a more general\n * schema. The keyword does not directly affect the validation result.\n *\n * This keyword's value MUST be an object. Each member value of this\n * object MUST be a valid JSON Schema.\n *\n * As an example, here is a schema describing an array of positive\n * integers, where the positive integer constraint is a subschema in\n * \"definitions\":\n * ```\n * {\n * \"type\": \"array\",\n * \"items\": { \"$ref\": \"#/definitions/positiveInteger\" },\n * \"definitions\": {\n * \"positiveInteger\": {\n * \"type\": \"integer\",\n * \"exclusiveMinimum\": 0\n * }\n * }\n * }\n * ```\n *\n * $defs is the newer keyword introduced in the JSON Schema Draft 2019-09, while definitions is from the older drafts.\n *\n * The main difference is that definitions is no longer an official keyword in the latest JSON Schema specification (Draft 2019-09 and later),\n * but it is still widely supported for backward compatibility.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-9\n */\n $defs?: Record<string, FormSchema>;\n\n /**\n * The \"definitions\" keywords provides a standardized location for\n * schema authors to inline re-usable JSON Schemas into a more general\n * schema. The keyword does not directly affect the validation result.\n *\n * This keyword's value MUST be an object. Each member value of this\n * object MUST be a valid JSON Schema.\n *\n * As an example, here is a schema describing an array of positive\n * integers, where the positive integer constraint is a subschema in\n * \"definitions\":\n * ```\n * {\n * \"type\": \"array\",\n * \"items\": { \"$ref\": \"#/definitions/positiveInteger\" },\n * \"definitions\": {\n * \"positiveInteger\": {\n * \"type\": \"integer\",\n * \"exclusiveMinimum\": 0\n * }\n * }\n * }\n * ```\n *\n * $defs is the newer keyword introduced in the JSON Schema Draft 2019-09, while definitions is from the older drafts.\n *\n * The main difference is that definitions is no longer an official keyword in the latest JSON Schema specification (Draft 2019-09 and later),\n * but it is still widely supported for backward compatibility.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-9\n */\n definitions?: Record<string, FormSchema>;\n}\n\n/**\n * Utility type for replacing object types with a specified type\n * @public\n */\nexport type ReplaceObjectType<T, AllowedType, ElseType> = T extends any[]\n ? ElseType\n : T extends Record<string, any>\n ? AllowedType\n : ElseType;\n\n/**\n * Utility type for supporting nested sub items in arrays\n * @public\n */\nexport type FormSchemaArrayItem<T> = T extends any[]\n ? FormSchema<T[Extract<keyof T, number>]>\n : FormSchema;\n\n/**\n * Utility type for recursive properties in a schema\n * @public\n */\nexport type FormSubKeySchema<TObj> = Partial<{\n [Key in Extract<keyof TObj, any>]: FormSchema<TObj[Key]>;\n}>;\n","/**\n * Defines the data for a table\n * @public\n */\nexport interface Column<T extends object = any> {\n /**\n * Column title to be displayed\n */\n title: string;\n\n /**\n * Name of the field in the data\n */\n field: keyof T;\n\n /**\n * Function to format the value before rendering\n */\n formatter?: TableFormatter;\n\n /**\n * Component used to render the field value\n */\n component?: TableComponentDefinition;\n\n /**\n * Type of aggregator to use for the column\n */\n aggregator?: ColumnAggregatorType | ColumnAggregatorFunction<T>;\n\n /**\n * A component used to render inside the column header\n */\n headerComponent?: TableComponentDefinition;\n\n /**\n * Sets the horizontal text alignment for the column\n */\n horizontalAlign?: 'left' | 'center' | 'right';\n\n /**\n * Defines whether end-user can sort a column\n */\n headerSort?: boolean;\n}\n\n/**\n * Definition for a formatter function\n * @param value - The value to be formatted\n * @param data - The data for the current row\n * @returns The formatted value\n * @public\n */\nexport type TableFormatter = (value: any, data?: object) => string;\n\n/**\n * The `component` key in the schema uses this interface to define a\n * component to be rendered inside a cell in the table.\n *\n * @note The table will display the component as `inline-block` in order\n * to give the column the correct size. If the component should have the\n * full width of the column, this might have to be overridden by setting\n * the display mode to `block`, e.g.\n *\n * ```css\n * :host(*) {\n * display: block !important;\n * }\n * ```\n * @public\n */\nexport interface TableComponentDefinition {\n /**\n * Name of the component\n */\n name: string;\n\n /**\n * Properties to send to the component\n */\n props?: Record<string, any>;\n\n /**\n * Factory for creating properties dynamically for a custom component.\n *\n * The properties returned from this function will be merged with the\n * `props` properties when the component is created.\n *\n * When the propsFactory is used for header components there will be no data available.\n *\n * @param data - The data for the current row\n * @returns Properties for the component\n */\n propsFactory?: (data: object) => Record<string, any>;\n}\n\n/**\n * Interface for custom components rendered inside a `limel-table`.\n * @public\n */\nexport interface TableComponent<T extends object = any> {\n /**\n * Name of the field being rendered\n */\n field?: string;\n\n /**\n * Value being rendered\n */\n value?: any;\n\n /**\n * Data for the current row of the table\n */\n data?: T;\n}\n\n/**\n * Indicates whether the specified column is sorted ascending or descending.\n * @public\n */\nexport interface ColumnSorter {\n /**\n * The column being sorted\n */\n column: Column;\n\n /**\n * The direction to sort on\n */\n direction: 'ASC' | 'DESC';\n}\n\n/**\n * Specifies the current page, and which columns the table is currently sorted on.\n * @public\n */\nexport interface TableParams {\n /**\n * The current page being set\n */\n page: number;\n\n /**\n * Sorters applied to the current page\n */\n sorters?: ColumnSorter[];\n}\n\n/**\n * The built-in aggregators available for columns\n * @public\n */\nexport enum ColumnAggregatorType {\n /**\n * Calculates the average value of all numerical cells in the column\n */\n Average = 'avg',\n\n /**\n * Displays the maximum value from all numerical cells in the column\n */\n Maximum = 'max',\n\n /**\n * Displays the minimum value from all numerical cells in the column\n */\n Minimum = 'min',\n\n /**\n * Displays the sum of all numerical cells in the column\n */\n Sum = 'sum',\n\n /**\n * Counts the number of non empty cells in the column\n */\n Count = 'count',\n}\n\n/**\n * Instead of using one of the built-in aggregators, it is possible to\n * define a custom aggregator function.\n *\n * @param column - the configuration for the column\n * @param values - list of all values to be aggregated\n * @param data - list of all objects to be aggregated\n * @returns the aggregated data\n *\n * @public\n */\nexport type ColumnAggregatorFunction<T = object> = (\n column?: Column,\n values?: any[],\n data?: T[],\n) => any;\n\n/**\n * Defines aggregate values for columns\n * @public\n */\nexport interface ColumnAggregate {\n /**\n * The name of the `Column` field\n */\n field: string;\n /**\n * The aggregate value\n */\n value: any;\n}\n\n/**\n * Data for identifying a row of the table\n * @public\n */\nexport type RowData = {\n id?: string | number;\n};\n"],"version":3}
1
+ {"file":"index.js","mappings":"AAwSA;;;;IAIY;AAAZ,WAAY,cAAc;;;;EAItB,qCAAmB,CAAA;;;;EAKnB,+BAAa,CAAA;;;;;;;;EASb,6BAAW,CAAA;AACf,CAAC,EAnBW,cAAc,KAAd,cAAc;;ACvJ1B;;;;IAIY;AAAZ,WAAY,oBAAoB;;;;EAI5B,uCAAe,CAAA;;;;EAKf,uCAAe,CAAA;;;;EAKf,uCAAe,CAAA;;;;EAKf,mCAAW,CAAA;;;;EAKX,uCAAe,CAAA;AACnB,CAAC,EAzBW,oBAAoB,KAApB,oBAAoB;;;;","names":[],"sources":["./src/components/form/form.types.ts","./src/components/table/table.types.ts"],"sourcesContent":["import { JSONSchema7 } from 'json-schema';\nimport { Help } from '../help/help.types';\nimport { EventEmitter } from '@stencil/core';\n\n/**\n * EventEmitter from `@stencil/core`.\n *\n * @public\n */\nexport { EventEmitter } from '@stencil/core';\n\ndeclare module 'json-schema' {\n interface JSONSchema7 {\n /**\n * @internal\n * Unique identifier for the schema\n */\n id?: string;\n\n /**\n * Lime elements specific options that can be specified in a schema\n */\n lime?: Omit<LimeSchemaOptions, 'layout'> & {\n layout?: Partial<LimeLayoutOptions>;\n };\n }\n}\n\n/**\n * @public\n */\nexport interface ValidationStatus {\n /**\n * True if the form is valid, false otherwise\n *\n * If the form is invalid, any errors can be found on the `errors` property\n */\n valid: boolean;\n\n /**\n * List of validation errors\n */\n errors?: FormError[];\n}\n\n/**\n * @public\n */\nexport interface FormError {\n /**\n * Name of the error\n */\n name: string;\n\n /**\n * Params of the error\n */\n params?: unknown;\n\n /**\n * Name of the invalid property\n */\n property: string;\n\n /**\n * Path to the property within the schema\n */\n schemaPath: string;\n\n /**\n * String describing the error\n */\n message: string;\n}\n\n/**\n * @public\n */\nexport type ValidationError = {\n /**\n * Name of the field the error belongs to\n */\n [key: string]: string[] | ValidationError;\n};\n\n/**\n * @public\n */\nexport interface FormComponent<T = any> {\n /**\n * The value of the current property\n */\n value: T;\n\n /**\n * Whether or not the current property is required\n */\n required?: boolean;\n\n /**\n * Whether or not the current property is readonly\n */\n readonly?: boolean;\n\n /**\n * Whether or not the current property is disabled\n */\n disabled?: boolean;\n\n /**\n * The label of the current property\n */\n label?: string;\n\n /**\n * The helper text for the current property\n */\n helperText?: string;\n\n /**\n * Additional contextual information about the form\n */\n formInfo?: FormInfo;\n\n /**\n * The event to emit when the value of the current property has changed\n */\n change: EventEmitter<T>;\n}\n\n/**\n * @public\n */\nexport interface FormInfo {\n /**\n * The schema of the current property\n */\n schema?: FormSchema;\n\n /**\n * The schema of the whole form\n */\n rootSchema?: FormSchema;\n\n /**\n * A tree of errors for this property and its children\n */\n errorSchema?: object;\n\n /**\n * The value of the whole form\n */\n rootValue?: any;\n\n /**\n * The name of the current property\n */\n name?: string;\n\n /**\n * Path to the property within the schema\n */\n schemaPath?: string[];\n}\n\n/**\n * Lime elements specific options that can be specified under the `lime` key in\n * a schema, e.g.\n *\n * ```ts\n * const schema = {\n * type: 'object',\n * lime: {\n * collapsible: true,\n * },\n * };\n * ```\n *\n * @public\n */\nexport interface LimeSchemaOptions {\n /**\n * When specified on an object it will render all sub components inside a\n * collapsible section\n */\n collapsible?: boolean;\n\n /**\n * When `collapsible` is `true`, set this to `false` to make the\n * collapsible section load in the open state.\n * Defaults to `true`.\n */\n collapsed?: boolean;\n\n /**\n * Will render the field using the specified component. The component\n * should implement the `FormComponent` interface\n */\n component?: FormComponentOptions;\n\n /**\n * When specified on an object it will render the sub components with the\n * specified layout\n */\n layout?: LimeLayoutOptions;\n\n /**\n * Mark the field as disabled\n */\n disabled?: boolean;\n\n help?: string | Partial<Help>;\n}\n\n/**\n * Options for a layout to be used in a form\n * @public\n */\nexport type LimeLayoutOptions = GridLayoutOptions & RowLayoutOptions;\n\n/**\n * Options for a component to be rendered inside a form\n *\n * @public\n */\nexport interface FormComponentOptions {\n /**\n * Name of the component\n */\n name?: string;\n\n /**\n * Extra properties to give the component in addition to the properties\n * specified on the `FormComponent` interface\n */\n props?: Record<string, any>;\n}\n\n/**\n * @public\n */\nexport interface FormLayoutOptions<\n T extends FormLayoutType | `${FormLayoutType}` = FormLayoutType.Default,\n> {\n /**\n * The type of layout to use\n */\n type: T;\n}\n\n/**\n * Layout options for a grid layout\n * @public\n */\nexport interface GridLayoutOptions\n extends FormLayoutOptions<FormLayoutType | `${FormLayoutType}`> {\n /**\n * When specified on a component within the grid, the component will take\n * up the the specified number of columns in the form\n */\n // eslint-disable-next-line no-magic-numbers\n colSpan?: 1 | 2 | 3 | 4 | 5 | 'all';\n\n /**\n * When specified on a component within the grid, the component will take\n * up the the specified number of rows in the form\n */\n rowSpan?: number;\n\n /**\n * Number of columns to use in the layout\n */\n // eslint-disable-next-line no-magic-numbers\n columns?: 1 | 2 | 3 | 4 | 5;\n\n /**\n * Attempts to fill in holes earlier in the grid, if smaller items come up\n * later. This may cause items to appear out-of-order, when doing so would\n * fill holes left by larger items. Defaults to `true`.\n */\n dense?: boolean;\n}\n\n/**\n * Layout options for a row layout\n * @public\n */\nexport interface RowLayoutOptions\n extends FormLayoutOptions<FormLayoutType | `${FormLayoutType}`> {\n /**\n * When specified on a field, the chosen icon will be displayed\n * on the left side of the row, beside the title.\n */\n icon?: string;\n}\n\n/**\n * Represents the layout types for a form.\n * @public\n */\nexport enum FormLayoutType {\n /**\n * The default layout\n */\n Default = 'default',\n\n /**\n * Render the form fields using a responsive grid layout\n */\n Grid = 'grid',\n\n /**\n * Render the form fields in full-width rows.\n * Each row can have a leading `icon`, and a field.\n * `title` and `description` provided by the schema will be placed\n * on the row itself, and not on the field.\n * This layout is good for creating UIs for user settings pages.\n */\n Row = 'row',\n}\n\n/**\n * Represents the JSON schema with Lime specific options\n * @public\n */\nexport interface FormSchema<T extends Record<string, any> = any>\n extends JSONSchema7 {\n /**\n * The value of \"items\" MUST be either a valid JSON Schema or an array\n * of valid JSON Schemas.\n *\n * This keyword determines how child instances validate for arrays, and\n * does not directly validate the immediate instance itself.\n *\n * If \"items\" is a schema, validation succeeds if all elements in the\n * array successfully validate against that schema.\n *\n * If \"items\" is an array of schemas, validation succeeds if each\n * element of the instance validates against the schema at the same\n * position, if any.\n *\n * Omitting this keyword has the same behavior as an empty schema.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.4.1\n */\n items?: FormSchemaArrayItem<T> | Array<FormSchemaArrayItem<T>>;\n\n /**\n * The value of \"items\" MUST be either a valid JSON Schema or an array\n * of valid JSON Schemas.\n *\n * This keyword determines how child instances validate for arrays, and\n * does not directly validate the immediate instance itself.\n *\n * If \"items\" is a schema, validation succeeds if all elements in the\n * array successfully validate against that schema.\n *\n * If \"items\" is an array of schemas, validation succeeds if each\n * element of the instance validates against the schema at the same\n * position, if any.\n *\n * Omitting this keyword has the same behavior as an empty schema.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.4.2\n */\n additionalItems?: FormSchemaArrayItem<T>;\n\n /**\n * The value of this keyword MUST be a valid JSON Schema.\n *\n * An array instance is valid against \"contains\" if at least one of its\n * elements is valid against the given schema.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.4.6\n */\n contains?: FormSchemaArrayItem<T>;\n\n /**\n * The value of this keyword MUST be an array. Elements of this array,\n * if any, MUST be strings, and MUST be unique.\n *\n * An object instance is valid against this keyword if every item in the\n * array is the name of a property in the instance.\n *\n * Omitting this keyword has the same behavior as an empty array.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.3\n */\n required?: Array<ReplaceObjectType<T, Extract<keyof T, string>, string>>;\n\n /**\n * The value of \"properties\" MUST be an object. Each value of this\n * object MUST be a valid JSON Schema.\n *\n * This keyword determines how child instances validate for objects, and\n * does not directly validate the immediate instance itself.\n *\n * Validation succeeds if, for each name that appears in both the\n * instance and as a name within this keyword's value, the child\n * instance for that name successfully validates against the\n * corresponding schema.\n *\n * Omitting this keyword has the same behavior as an empty object.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.4\n */\n properties?: ReplaceObjectType<\n T,\n FormSubKeySchema<T>,\n Record<string, FormSchema>\n >;\n\n /**\n * This keyword's value MUST be a non-empty array. Each item of the\n * array MUST be a valid JSON Schema.\n *\n * An instance validates successfully against this keyword if it\n * validates successfully against all schemas defined by this keyword's\n * value.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.7.1\n */\n allOf?: Array<FormSchemaArrayItem<T>>;\n\n /**\n * This keyword's value MUST be a non-empty array. Each item of the\n * array MUST be a valid JSON Schema.\n *\n * An instance validates successfully against this keyword if it\n * validates successfully against at least one schema defined by this\n * keyword's value.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.7.2\n */\n anyOf?: Array<FormSchemaArrayItem<T>>;\n\n /**\n * This keyword's value MUST be a non-empty array. Each item of the\n * array MUST be a valid JSON Schema.\n *\n * An instance validates successfully against this keyword if it\n * validates successfully against exactly one schema defined by this\n * keyword's value.\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.7.3\n */\n oneOf?: Array<FormSchemaArrayItem<T>>;\n\n /**\n * The value of \"patternProperties\" MUST be an object. Each property\n * name of this object SHOULD be a valid regular expression, according\n * to the ECMA 262 regular expression dialect. Each property value of\n * this object MUST be a valid JSON Schema.\n *\n * This keyword determines how child instances validate for objects, and\n * does not directly validate the immediate instance itself. Validation\n * of the primitive instance type against this keyword always succeeds.\n *\n * Validation succeeds if, for each instance name that matches any\n * regular expressions that appear as a property name in this keyword's\n * value, the child instance for that name successfully validates\n * against each schema that corresponds to a matching regular\n * expression.\n *\n * Omitting this keyword has the same behavior as an empty object.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.5\n */\n patternProperties?: Record<string, FormSchema>;\n\n /**\n * The value of \"additionalProperties\" MUST be a valid JSON Schema.\n *\n * This keyword determines how child instances validate for objects, and\n * does not directly validate the immediate instance itself.\n *\n * Validation with \"additionalProperties\" applies only to the child\n * values of instance names that do not match any names in \"properties\",\n * and do not match any regular expression in \"patternProperties\".\n *\n * For all such properties, validation succeeds if the child instance\n * validates against the \"additionalProperties\" schema.\n *\n * Omitting this keyword has the same behavior as an empty schema.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.6\n */\n additionalProperties?: FormSchema | boolean;\n\n /**\n * This keyword specifies rules that are evaluated if the instance is an\n * object and contains a certain property.\n *\n * This keyword's value MUST be an object. Each property specifies a\n * dependency. Each dependency value MUST be an array or a valid JSON\n * Schema.\n *\n * If the dependency value is a subschema, and the dependency key is a\n * property in the instance, the entire instance must validate against\n * the dependency value.\n *\n * If the dependency value is an array, each element in the array, if\n * any, MUST be a string, and MUST be unique. If the dependency key is\n * a property in the instance, each of the items in the dependency value\n * must be a property that exists in the instance.\n *\n * Omitting this keyword has the same behavior as an empty object.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.7\n */\n dependencies?: Record<string, FormSchema | string[]>;\n\n /**\n * The value of \"propertyNames\" MUST be a valid JSON Schema.\n *\n * If the instance is an object, this keyword validates if every\n * property name in the instance validates against the provided schema.\n * Note the property name that the schema is testing will always be a\n * string.\n *\n * Omitting this keyword has the same behavior as an empty schema.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.5.8\n */\n propertyNames?: FormSchema;\n\n /**\n * This keyword's value MUST be a valid JSON Schema.\n *\n * This validation outcome of this keyword's subschema has no direct\n * effect on the overall validation result. Rather, it controls which\n * of the \"then\" or \"else\" keywords are evaluated.\n *\n * Instances that successfully validate against this keyword's subschema\n * MUST also be valid against the subschema value of the \"then\" keyword,\n * if present.\n *\n * Instances that fail to validate against this keyword's subschema MUST\n * also be valid against the subschema value of the \"else\" keyword, if\n * present.\n *\n * If annotations (Section 3.3) are being collected, they are collected\n * from this keyword's subschema in the usual way, including when the\n * keyword is present without either \"then\" or \"else\".\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.6.1\n */\n if?: FormSchema;\n\n /**\n * This keyword's value MUST be a valid JSON Schema.\n *\n * This validation outcome of this keyword's subschema has no direct\n * effect on the overall validation result. Rather, it controls which\n * of the \"then\" or \"else\" keywords are evaluated.\n *\n * Instances that successfully validate against this keyword's subschema\n * MUST also be valid against the subschema value of the \"then\" keyword,\n * if present.\n *\n * Instances that fail to validate against this keyword's subschema MUST\n * also be valid against the subschema value of the \"else\" keyword, if\n * present.\n *\n * If annotations (Section 3.3) are being collected, they are collected\n * from this keyword's subschema in the usual way, including when the\n * keyword is present without either \"then\" or \"else\".\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.6.2\n */\n then?: FormSchema;\n\n /**\n * This keyword's value MUST be a valid JSON Schema.\n *\n * When \"if\" is present, and the instance fails to validate against its\n * subschema, then valiation succeeds against this keyword if the\n * instance successfully validates against this keyword's subschema.\n *\n * This keyword has no effect when \"if\" is absent, or when the instance\n * successfully validates against its subschema. Implementations MUST\n * NOT evaluate the instance against this keyword, for either validation\n * or annotation collection purposes, in such cases.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.6.3\n */\n else?: FormSchema;\n\n /**\n * This keyword's value MUST be a valid JSON Schema.\n *\n * An instance is valid against this keyword if it fails to validate\n * successfully against the schema defined by this keyword.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.7.4\n */\n not?: FormSchema;\n\n /**\n * The \"$defs\" keywords provides a standardized location for\n * schema authors to inline re-usable JSON Schemas into a more general\n * schema. The keyword does not directly affect the validation result.\n *\n * This keyword's value MUST be an object. Each member value of this\n * object MUST be a valid JSON Schema.\n *\n * As an example, here is a schema describing an array of positive\n * integers, where the positive integer constraint is a subschema in\n * \"definitions\":\n * ```\n * {\n * \"type\": \"array\",\n * \"items\": { \"$ref\": \"#/definitions/positiveInteger\" },\n * \"definitions\": {\n * \"positiveInteger\": {\n * \"type\": \"integer\",\n * \"exclusiveMinimum\": 0\n * }\n * }\n * }\n * ```\n *\n * $defs is the newer keyword introduced in the JSON Schema Draft 2019-09, while definitions is from the older drafts.\n *\n * The main difference is that definitions is no longer an official keyword in the latest JSON Schema specification (Draft 2019-09 and later),\n * but it is still widely supported for backward compatibility.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-9\n */\n $defs?: Record<string, FormSchema>;\n\n /**\n * The \"definitions\" keywords provides a standardized location for\n * schema authors to inline re-usable JSON Schemas into a more general\n * schema. The keyword does not directly affect the validation result.\n *\n * This keyword's value MUST be an object. Each member value of this\n * object MUST be a valid JSON Schema.\n *\n * As an example, here is a schema describing an array of positive\n * integers, where the positive integer constraint is a subschema in\n * \"definitions\":\n * ```\n * {\n * \"type\": \"array\",\n * \"items\": { \"$ref\": \"#/definitions/positiveInteger\" },\n * \"definitions\": {\n * \"positiveInteger\": {\n * \"type\": \"integer\",\n * \"exclusiveMinimum\": 0\n * }\n * }\n * }\n * ```\n *\n * $defs is the newer keyword introduced in the JSON Schema Draft 2019-09, while definitions is from the older drafts.\n *\n * The main difference is that definitions is no longer an official keyword in the latest JSON Schema specification (Draft 2019-09 and later),\n * but it is still widely supported for backward compatibility.\n *\n * @see https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-9\n */\n definitions?: Record<string, FormSchema>;\n}\n\n/**\n * Utility type for replacing object types with a specified type\n * @public\n */\nexport type ReplaceObjectType<T, AllowedType, ElseType> = T extends any[]\n ? ElseType\n : T extends Record<string, any>\n ? AllowedType\n : ElseType;\n\n/**\n * Utility type for supporting nested sub items in arrays\n * @public\n */\nexport type FormSchemaArrayItem<T> = T extends any[]\n ? FormSchema<T[Extract<keyof T, number>]>\n : FormSchema;\n\n/**\n * Utility type for recursive properties in a schema\n * @public\n */\nexport type FormSubKeySchema<TObj> = Partial<{\n [Key in Extract<keyof TObj, any>]: FormSchema<TObj[Key]>;\n}>;\n","/**\n * Defines the data for a table\n * @public\n */\nexport interface Column<T extends object = any> {\n /**\n * Column title to be displayed\n */\n title: string;\n\n /**\n * Name of the field in the data\n */\n field: keyof T;\n\n /**\n * Function to format the value before rendering\n */\n formatter?: TableFormatter;\n\n /**\n * Component used to render the field value\n */\n component?: TableComponentDefinition;\n\n /**\n * Type of aggregator to use for the column\n */\n aggregator?: ColumnAggregatorType | ColumnAggregatorFunction<T>;\n\n /**\n * A component used to render inside the column header\n */\n headerComponent?: TableComponentDefinition;\n\n /**\n * Sets the horizontal text alignment for the column\n */\n horizontalAlign?: 'left' | 'center' | 'right';\n\n /**\n * Defines whether end-user can sort a column\n */\n headerSort?: boolean;\n}\n\n/**\n * Definition for a formatter function\n * @param value - The value to be formatted\n * @param data - The data for the current row\n * @returns The formatted value\n * @public\n */\nexport type TableFormatter = (value: any, data?: object) => string;\n\n/**\n * The `component` key in the schema uses this interface to define a\n * component to be rendered inside a cell in the table.\n *\n * @note The table will display the component as `inline-block` in order\n * to give the column the correct size. If the component should have the\n * full width of the column, this might have to be overridden by setting\n * the display mode to `block`, e.g.\n *\n * ```css\n * :host(*) {\n * display: block !important;\n * }\n * ```\n * @public\n */\nexport interface TableComponentDefinition {\n /**\n * Name of the component\n */\n name: string;\n\n /**\n * Properties to send to the component\n */\n props?: Record<string, any>;\n\n /**\n * Factory for creating properties dynamically for a custom component.\n *\n * The properties returned from this function will be merged with the\n * `props` properties when the component is created.\n *\n * When the propsFactory is used for header components there will be no data available.\n *\n * @param data - The data for the current row\n * @returns Properties for the component\n */\n propsFactory?: (data: object) => Record<string, any>;\n}\n\n/**\n * Interface for custom components rendered inside a `limel-table`.\n * @public\n */\nexport interface TableComponent<T extends object = any> {\n /**\n * Name of the field being rendered\n */\n field?: string;\n\n /**\n * Value being rendered\n */\n value?: any;\n\n /**\n * Data for the current row of the table\n */\n data?: T;\n}\n\n/**\n * Indicates whether the specified column is sorted ascending or descending.\n * @public\n */\nexport interface ColumnSorter {\n /**\n * The column being sorted\n */\n column: Column;\n\n /**\n * The direction to sort on\n */\n direction: 'ASC' | 'DESC';\n}\n\n/**\n * Specifies the current page, and which columns the table is currently sorted on.\n * @public\n */\nexport interface TableParams {\n /**\n * The current page being set\n */\n page: number;\n\n /**\n * Sorters applied to the current page\n */\n sorters?: ColumnSorter[];\n}\n\n/**\n * The built-in aggregators available for columns\n * @public\n */\nexport enum ColumnAggregatorType {\n /**\n * Calculates the average value of all numerical cells in the column\n */\n Average = 'avg',\n\n /**\n * Displays the maximum value from all numerical cells in the column\n */\n Maximum = 'max',\n\n /**\n * Displays the minimum value from all numerical cells in the column\n */\n Minimum = 'min',\n\n /**\n * Displays the sum of all numerical cells in the column\n */\n Sum = 'sum',\n\n /**\n * Counts the number of non empty cells in the column\n */\n Count = 'count',\n}\n\n/**\n * Instead of using one of the built-in aggregators, it is possible to\n * define a custom aggregator function.\n *\n * @param column - the configuration for the column\n * @param values - list of all values to be aggregated\n * @param data - list of all objects to be aggregated\n * @returns the aggregated data\n *\n * @public\n */\nexport type ColumnAggregatorFunction<T = object> = (\n column?: Column,\n values?: any[],\n data?: T[],\n) => any;\n\n/**\n * Defines aggregate values for columns\n * @public\n */\nexport interface ColumnAggregate {\n /**\n * The name of the `Column` field\n */\n field: string;\n /**\n * The aggregate value\n */\n value: any;\n}\n\n/**\n * Data for identifying a row of the table\n * @public\n */\nexport type RowData = {\n id?: string | number;\n};\n"],"version":3}
@@ -9,7 +9,6 @@ import { g as getPrototype } from './_getPrototype-8096728a.js';
9
9
  import { i as isArray } from './isArray-80298bc7.js';
10
10
  import { i as isObjectLike } from './isObjectLike-38996507.js';
11
11
  import { d as decodeHTML, m as markdownToHTML, s as sanitizeHTML } from './markdown-parser-47476fc0.js';
12
- import { I as ImageState } from './text-editor.types-e82469d1.js';
13
12
  import { t as translate$1 } from './translations-489f20b3.js';
14
13
  import { c as createRandomString } from './random-string-e74dc48d.js';
15
14
  import { i as isItem } from './isItem-b0459122.js';
@@ -25929,39 +25928,38 @@ function hasImageNode(node) {
25929
25928
  return false;
25930
25929
  }
25931
25930
  function createImageNodeMarkdownSerializer(language) {
25932
- return (state, node) => {
25933
- if (node.attrs.state === ImageState.FAILED) {
25934
- const text = translate$1.get('editor-image-view.failed', language, {
25935
- filename: node.attrs.alt || 'file',
25936
- });
25937
- state.write(`<span>${text}</span>`);
25931
+ return (markdownSerializerState, node) => {
25932
+ const { state, alt, src, width, maxWidth } = node.attrs;
25933
+ if (!isEditorImageState(state)) {
25938
25934
  return;
25939
25935
  }
25940
- else if (node.attrs.state === ImageState.LOADING) {
25941
- const text = translate$1.get('editor-image-view.loading', language, {
25942
- filename: node.attrs.alt || 'file',
25943
- });
25944
- state.write(`<span>${text}</span>`);
25936
+ if (state === 'success') {
25937
+ const imageHTML = getImageHTML(src, alt, width, maxWidth);
25938
+ markdownSerializerState.write(imageHTML);
25945
25939
  return;
25946
25940
  }
25947
- let imageHTML = `<img src="${node.attrs.src}"`;
25948
- if (node.attrs.alt) {
25949
- imageHTML += ` alt="${node.attrs.alt}"`;
25950
- }
25951
- const style = [];
25952
- if (node.attrs.width) {
25953
- style.push(`width: ${node.attrs.width};`);
25954
- }
25955
- if (node.attrs.maxWidth) {
25956
- style.push(`max-width: ${node.attrs.maxWidth};`);
25957
- }
25958
- if (style.length > 0) {
25959
- imageHTML += ` style="${style.join(' ')}"`;
25960
- }
25961
- imageHTML += ' />';
25962
- state.write(imageHTML);
25941
+ const statusHTML = getStatusHTML(state, alt, language);
25942
+ markdownSerializerState.write(statusHTML);
25963
25943
  };
25964
25944
  }
25945
+ function getStatusHTML(state, alt, language) {
25946
+ const key = state === 'failed' ? 'failed' : 'loading';
25947
+ const text = translate$1.get(`editor-image-view.${key}`, language, {
25948
+ filename: alt || 'file',
25949
+ });
25950
+ return `<span>${text}</span>`;
25951
+ }
25952
+ function getImageHTML(src, alt, width, maxWidth) {
25953
+ const style = [];
25954
+ if (width) {
25955
+ style.push(`width: ${width};`);
25956
+ }
25957
+ if (maxWidth) {
25958
+ style.push(`max-width: ${maxWidth};`);
25959
+ }
25960
+ const styleAttribute = style.length > 0 ? ` style="${style.join(' ')}"` : '';
25961
+ return `<img src="${src}" alt="${alt}"${styleAttribute} />`;
25962
+ }
25965
25963
  function createImageNodeSpec(language) {
25966
25964
  return {
25967
25965
  group: 'inline',
@@ -25972,24 +25970,16 @@ function createImageNodeSpec(language) {
25972
25970
  fileInfoId: { default: '' },
25973
25971
  width: { default: '' },
25974
25972
  maxWidth: { default: '100%' },
25975
- state: { default: '' },
25973
+ state: { default: 'success' },
25976
25974
  },
25977
25975
  toDOM: (node) => {
25978
- if (node.attrs.state === ImageState.FAILED) {
25979
- return createStatusSpan('failed', node, language);
25980
- }
25981
- else if (node.attrs.state === ImageState.LOADING) {
25982
- return createStatusSpan('loading', node, language);
25983
- }
25984
- let img = imageCache.get(node.attrs.fileInfoId);
25985
- if (img) {
25986
- updateImageElement(img, node);
25976
+ if (!isEditorImageState(node.attrs.state)) {
25977
+ return;
25987
25978
  }
25988
- else {
25989
- img = createImageElement(node);
25990
- imageCache.set(node.attrs.fileInfoId, img);
25979
+ if (node.attrs.state === 'success') {
25980
+ return getOrCreateImageElement(node.attrs.fileInfoId, node);
25991
25981
  }
25992
- return img;
25982
+ return createStatusSpanForState(node.attrs.state, node, language);
25993
25983
  },
25994
25984
  parseDOM: [
25995
25985
  {
@@ -26000,7 +25990,7 @@ function createImageNodeSpec(language) {
26000
25990
  alt: dom.getAttribute('alt') || 'file',
26001
25991
  width: dom.style.width || '',
26002
25992
  maxWidth: '100%',
26003
- state: ImageState.SUCCESS,
25993
+ state: 'success',
26004
25994
  fileInfoId: crypto.randomUUID(),
26005
25995
  };
26006
25996
  },
@@ -26008,6 +25998,24 @@ function createImageNodeSpec(language) {
26008
25998
  ],
26009
25999
  };
26010
26000
  }
26001
+ function isEditorImageState(state) {
26002
+ return state === 'loading' || state === 'failed' || state === 'success';
26003
+ }
26004
+ function getOrCreateImageElement(fileInfoId, node) {
26005
+ let img = imageCache.get(fileInfoId);
26006
+ if (img) {
26007
+ updateImageElement(img, node);
26008
+ }
26009
+ else {
26010
+ img = createImageElement(node);
26011
+ imageCache.set(fileInfoId, img);
26012
+ }
26013
+ return img;
26014
+ }
26015
+ function createStatusSpanForState(state, node, language) {
26016
+ const statusKey = state === 'failed' ? 'failed' : 'loading';
26017
+ return createStatusSpan(statusKey, node, language);
26018
+ }
26011
26019
  function createStatusSpan(key, node, language) {
26012
26020
  const text = translate$1.get(`editor-image-view.${key}`, language, {
26013
26021
  filename: node.attrs.alt || 'file',
@@ -26299,7 +26307,7 @@ const createLinkPlugin = (updateLinkCallback) => {
26299
26307
  };
26300
26308
 
26301
26309
  const pluginKey = new PluginKey('imageInserterPlugin');
26302
- const createImageInserterPlugin = (imagePastedCallback, imageRemovedCallback) => {
26310
+ const createImageInserterPlugin = (imagePastedCallback) => {
26303
26311
  return new Plugin({
26304
26312
  key: pluginKey,
26305
26313
  props: {
@@ -26312,40 +26320,7 @@ const createImageInserterPlugin = (imagePastedCallback, imageRemovedCallback) =>
26312
26320
  },
26313
26321
  },
26314
26322
  },
26315
- state: {
26316
- init: () => {
26317
- return { insertedImages: {} };
26318
- },
26319
- apply: (tr, pluginState) => {
26320
- const newState = Object.assign({}, pluginState);
26321
- newState.insertedImages = getImagesFromTransaction(tr);
26322
- findAndHandleRemovedImages(imageRemovedCallback, pluginState.insertedImages, newState.insertedImages);
26323
- return newState;
26324
- },
26325
- },
26326
- });
26327
- };
26328
- const getImagesFromTransaction = (tr) => {
26329
- const images = {};
26330
- tr.doc.descendants((node) => {
26331
- if (node.type.name === 'image') {
26332
- images[node.attrs.fileInfoId] = node;
26333
- }
26334
26323
  });
26335
- return images;
26336
- };
26337
- const findAndHandleRemovedImages = (imageRemovedCallback, previousImages, newImages) => {
26338
- const removedKeys = Object.keys(previousImages).filter((key) => !(key in newImages));
26339
- for (const removedKey of removedKeys) {
26340
- const removedImage = previousImages[removedKey];
26341
- const imageInfo = {
26342
- fileInfoId: removedImage.attrs.fileInfoId,
26343
- src: removedImage.attrs.src,
26344
- state: removedImage.attrs.state,
26345
- };
26346
- imageRemovedCallback(imageInfo);
26347
- imageCache.delete(removedImage.attrs.fileInfoId);
26348
- }
26349
26324
  };
26350
26325
  const imageInserterFactory = (view, base64Data, fileInfo) => {
26351
26326
  return {
@@ -26358,12 +26333,8 @@ const imageInserterFactory = (view, base64Data, fileInfo) => {
26358
26333
  const createThumbnailInserter = (view, base64Data, fileInfo) => () => {
26359
26334
  const { state, dispatch } = view;
26360
26335
  const { schema } = state;
26361
- const placeholderNode = schema.nodes.image.create({
26362
- src: base64Data,
26363
- alt: fileInfo.filename,
26364
- fileInfoId: fileInfo.id,
26365
- state: ImageState.LOADING,
26366
- });
26336
+ const imageNodeAttrs = createImageNodeAttrs(base64Data, fileInfo, 'loading');
26337
+ const placeholderNode = schema.nodes.image.create(imageNodeAttrs);
26367
26338
  const transaction = state.tr.replaceSelectionWith(placeholderNode);
26368
26339
  dispatch(transaction);
26369
26340
  };
@@ -26373,12 +26344,8 @@ const createImageInserter = (view, fileInfo) => (src) => {
26373
26344
  const tr = state.tr;
26374
26345
  state.doc.descendants((node, pos) => {
26375
26346
  if (node.attrs.fileInfoId === fileInfo.id) {
26376
- const imageNode = schema.nodes.image.create({
26377
- src: src ? src : node.attrs.src,
26378
- alt: fileInfo.filename,
26379
- fileInfoId: fileInfo.id,
26380
- state: ImageState.SUCCESS,
26381
- });
26347
+ const imageNodeAttrs = createImageNodeAttrs(src ? src : node.attrs.src, fileInfo, 'success');
26348
+ const imageNode = schema.nodes.image.create(imageNodeAttrs);
26382
26349
  tr.replaceWith(pos, pos + node.nodeSize, imageNode);
26383
26350
  return false;
26384
26351
  }
@@ -26391,31 +26358,35 @@ const createFailedThumbnailInserter = (view, fileInfo) => () => {
26391
26358
  const tr = state.tr;
26392
26359
  state.doc.descendants((node, pos) => {
26393
26360
  if (node.attrs.fileInfoId === fileInfo.id) {
26394
- const errorPlaceholderNode = schema.nodes.image.create({
26395
- src: node.attrs.src,
26396
- alt: fileInfo.filename,
26397
- fileInfoId: fileInfo.id,
26398
- state: ImageState.FAILED,
26399
- });
26361
+ const imageNodeAttrs = createImageNodeAttrs(node.attrs.src, fileInfo, 'failed');
26362
+ const errorPlaceholderNode = schema.nodes.image.create(imageNodeAttrs);
26400
26363
  tr.replaceWith(pos, pos + node.nodeSize, errorPlaceholderNode);
26401
26364
  return false;
26402
26365
  }
26403
26366
  });
26404
26367
  dispatch(tr);
26405
26368
  };
26369
+ function createImageNodeAttrs(src, fileInfo, state) {
26370
+ return {
26371
+ src: src,
26372
+ alt: fileInfo.filename,
26373
+ fileInfoId: fileInfo.id,
26374
+ state: state,
26375
+ };
26376
+ }
26406
26377
  /**
26407
26378
  * Check if a given ProseMirror node or fragment contains any image nodes.
26408
26379
  * @param node - The ProseMirror node or fragment to check.
26409
26380
  * @returns A boolean indicating whether the node contains any image nodes.
26410
26381
  */
26411
- const isImageNode = (node) => {
26382
+ const isImageNode$1 = (node) => {
26412
26383
  if (node instanceof Node$1) {
26413
26384
  if (node.type.name === 'image') {
26414
26385
  return true;
26415
26386
  }
26416
26387
  let found = false;
26417
26388
  node.content.forEach((child) => {
26418
- if (isImageNode(child)) {
26389
+ if (isImageNode$1(child)) {
26419
26390
  found = true;
26420
26391
  }
26421
26392
  });
@@ -26424,7 +26395,7 @@ const isImageNode = (node) => {
26424
26395
  else if (node instanceof Fragment) {
26425
26396
  let found = false;
26426
26397
  node.forEach((child) => {
26427
- if (isImageNode(child)) {
26398
+ if (isImageNode$1(child)) {
26428
26399
  found = true;
26429
26400
  }
26430
26401
  });
@@ -26440,7 +26411,7 @@ const isImageNode = (node) => {
26440
26411
  const filterImageNodes = (fragment) => {
26441
26412
  const filteredChildren = [];
26442
26413
  fragment.forEach((child) => {
26443
- if (!isImageNode(child)) {
26414
+ if (!isImageNode$1(child)) {
26444
26415
  if (child.content.size > 0) {
26445
26416
  const filteredContent = filterImageNodes(child.content);
26446
26417
  const newNode = child.copy(filteredContent);
@@ -26579,21 +26550,20 @@ class ImageView {
26579
26550
  });
26580
26551
  };
26581
26552
  this.transitionBetweenStates = () => {
26553
+ var _a;
26582
26554
  this.cleanUpPreviousState();
26583
26555
  this.dom.className = `image-wrapper state-${this.node.attrs.state}`;
26584
- if (this.node.attrs.state === ImageState.LOADING) {
26585
- this.createLoadingState();
26586
- }
26587
- else if (this.node.attrs.state === ImageState.SUCCESS) {
26588
- this.createSuccessState();
26589
- }
26590
- else if (this.node.attrs.state === ImageState.FAILED) {
26591
- this.createFailedState();
26592
- }
26556
+ const stateHandlers = {
26557
+ loading: this.createLoadingState,
26558
+ success: this.createSuccessState,
26559
+ failed: this.createFailedState,
26560
+ };
26561
+ const state = this.node.attrs.state;
26562
+ (_a = stateHandlers[state]) === null || _a === void 0 ? void 0 : _a.call(stateHandlers);
26593
26563
  };
26594
26564
  this.transitioningBetweenSuccessStates = (newNode) => {
26595
- return (this.node.attrs.state === ImageState.SUCCESS &&
26596
- newNode.attrs.state === ImageState.SUCCESS);
26565
+ return (this.node.attrs.state === 'success' &&
26566
+ newNode.attrs.state === 'success');
26597
26567
  };
26598
26568
  this.node = node;
26599
26569
  this.view = view;
@@ -28316,6 +28286,114 @@ const getTableNodes = () => {
28316
28286
  });
28317
28287
  };
28318
28288
 
28289
+ /**
28290
+ * Extracts metadata from a ProseMirror document node
28291
+ *
28292
+ * This function traverses the entire document tree and collects information about
28293
+ * special elements like images and links.
28294
+ *
28295
+ * @param doc - The ProseMirror document node to extract metadata from
28296
+ * @returns A metadata object containing arrays of images and links found in the document
28297
+ */
28298
+ function getMetadataFromDoc(doc) {
28299
+ const metadata = { images: [], links: [] };
28300
+ doc.descendants((node) => {
28301
+ if (isImageNode(node)) {
28302
+ metadata.images.push(extractImageMetadata(node));
28303
+ }
28304
+ else if (isTextNodeWithMarks(node)) {
28305
+ extractLinkMetadata(node).forEach((link) => metadata.links.push(link));
28306
+ }
28307
+ return true;
28308
+ });
28309
+ return metadata;
28310
+ }
28311
+ function isImageNode(node) {
28312
+ return node.type.name === 'image' && !!node.attrs;
28313
+ }
28314
+ function extractImageMetadata(node) {
28315
+ return {
28316
+ src: node.attrs.src,
28317
+ state: node.attrs.state,
28318
+ fileInfoId: node.attrs.fileInfoId,
28319
+ };
28320
+ }
28321
+ function isTextNodeWithMarks(node) {
28322
+ var _a;
28323
+ return node.isText && ((_a = node.marks) === null || _a === void 0 ? void 0 : _a.length) > 0;
28324
+ }
28325
+ function extractLinkMetadata(node) {
28326
+ return node.marks
28327
+ .filter((mark) => mark.type.name === 'link' && mark.attrs)
28328
+ .map((mark) => ({
28329
+ href: mark.attrs.href,
28330
+ text: node.text,
28331
+ }));
28332
+ }
28333
+ /**
28334
+ * Determines if metadata has changed between two states
28335
+ * Handles duplicates correctly but is order-insensitive
28336
+ *
28337
+ * @param oldMetadata - The previous metadata state to compare against
28338
+ * @param newMetadata - The current metadata state
28339
+ * @returns True if there are any differences between the metadata objects, false otherwise
28340
+ */
28341
+ function hasMetadataChanged(oldMetadata, newMetadata) {
28342
+ return (hasDifferentLengths(oldMetadata, newMetadata) ||
28343
+ hasDifferentLinks(oldMetadata.links, newMetadata.links) ||
28344
+ hasDifferentImages(oldMetadata.images, newMetadata.images));
28345
+ }
28346
+ function hasDifferentLengths(oldMetadata, newMetadata) {
28347
+ return (oldMetadata.images.length !== newMetadata.images.length ||
28348
+ oldMetadata.links.length !== newMetadata.links.length);
28349
+ }
28350
+ function hasDifferentLinks(oldLinks, newLinks) {
28351
+ const oldLinkCounts = getLinkFrequencyMap(oldLinks);
28352
+ const newLinkCounts = getLinkFrequencyMap(newLinks);
28353
+ return !areFrequencyMapsEqual(oldLinkCounts, newLinkCounts);
28354
+ }
28355
+ function hasDifferentImages(oldImages, newImages) {
28356
+ const oldImageCounts = getImageFrequencyMap(oldImages);
28357
+ const newImageCounts = getImageFrequencyMap(newImages);
28358
+ return !areFrequencyMapsEqual(oldImageCounts, newImageCounts);
28359
+ }
28360
+ /**
28361
+ * Creates a frequency map for images based on their key properties
28362
+ */
28363
+ function getImageFrequencyMap(images) {
28364
+ const countMap = new Map();
28365
+ images.forEach((image) => {
28366
+ const key = `${image.fileInfoId}|${image.state}|${image.src}`;
28367
+ countMap.set(key, (countMap.get(key) || 0) + 1);
28368
+ });
28369
+ return countMap;
28370
+ }
28371
+ /**
28372
+ * Creates a frequency map for links based on their key properties
28373
+ */
28374
+ function getLinkFrequencyMap(links) {
28375
+ const countMap = new Map();
28376
+ links.forEach((link) => {
28377
+ const key = `${link.href}|${link.text}`;
28378
+ countMap.set(key, (countMap.get(key) || 0) + 1);
28379
+ });
28380
+ return countMap;
28381
+ }
28382
+ /**
28383
+ * Compares two frequency maps for equality
28384
+ */
28385
+ function areFrequencyMapsEqual(map1, map2) {
28386
+ if (map1.size !== map2.size) {
28387
+ return false;
28388
+ }
28389
+ for (const [key, count] of map1.entries()) {
28390
+ if (map2.get(key) !== count) {
28391
+ return false;
28392
+ }
28393
+ }
28394
+ return true;
28395
+ }
28396
+
28319
28397
  const prosemirrorAdapterCss = "@charset \"UTF-8\";:host{--mdc-theme-primary:var(\n --lime-primary-color,\n rgb(var(--color-teal-default))\n );--mdc-theme-secondary:var(\n --lime-secondary-color,\n rgb(var(--contrast-1100))\n );--mdc-theme-on-primary:var(\n --lime-on-primary-color,\n rgb(var(--contrast-100))\n );--mdc-theme-on-secondary:var(\n --lime-on-secondary-color,\n rgb(var(--contrast-100))\n );--mdc-theme-text-disabled-on-background:var(\n --lime-text-disabled-on-background-color,\n rgba(var(--contrast-1700), 0.38)\n );--mdc-theme-text-primary-on-background:var(\n --lime-text-primary-on-background-color,\n rgba(var(--contrast-1700), 0.87)\n );--mdc-theme-text-secondary-on-background:var(\n --lime-text-secondary-on-background-color,\n rgba(var(--contrast-1700), 0.54)\n );--mdc-theme-error:var(\n --lime-error-background-color,\n rgb(var(--color-red-dark))\n );--lime-error-text-color:rgb(var(--color-red-darker));--mdc-theme-surface:var(\n --lime-surface-background-color,\n rgb(var(--contrast-100))\n );--mdc-theme-on-surface:var(\n --lime-on-surface-color,\n rgb(var(--contrast-1500))\n )}blockquote{position:relative;font-weight:100;font-size:0.875rem;max-width:100%;line-height:1.4;margin:0;padding:0.5rem 1.25rem;border-radius:0.05rem 0.75rem;background-color:rgb(var(--contrast-300))}blockquote:before,blockquote:after{position:absolute;font-size:2.75rem;opacity:0.4}blockquote:before{content:\"“\";left:0;top:-0.75rem}blockquote:after{content:\"”\";right:0;bottom:-2rem}:host(limel-markdown.truncate-paragraphs) p{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}p,li{font-size:0.875rem;word-break:break-word}a{word-break:break-all}p{margin-top:0;margin-bottom:0.5rem}p:only-child{margin-bottom:0}a{transition:color 0.2s ease;color:var(--markdown-hyperlink-color, rgb(var(--color-blue-dark)));text-decoration:none}a:hover{color:var(--markdown-hyperlink-color--hovered, rgb(var(--color-blue-default)))}hr{margin:1.75rem 0 2rem 0;border-width:0;border-top:1px solid rgb(var(--contrast-500))}dl{display:grid;grid-template-columns:1fr 2fr;grid-template-rows:1fr;margin-bottom:2rem;border:1px solid rgb(var(--contrast-400));border-radius:0.375rem;background-color:rgb(var(--contrast-200))}dl dt,dl dd{padding:0.375rem 0.5rem;font-size:0.875rem;margin:0}dl dt:nth-of-type(even),dl dd:nth-of-type(even){background-color:rgb(var(--contrast-300))}dl dt:first-child{border-top-left-radius:0.375rem}dl dt:last-child{border-bottom-left-radius:0.375rem}dl dd:first-child{border-top-right-radius:0.375rem}dl dd:last-child{border-bottom-right-radius:0.375rem}h1{font-size:1.5rem}h2{font-size:1.25rem}h3{font-size:1.125rem}h4{font-size:1rem}h5{font-size:0.875rem}h6{font-size:0.75rem}h1,h2{margin-top:0.5rem;margin-bottom:0.5rem;letter-spacing:-0.03125rem;font-weight:500}h3,h4{margin-top:0.75rem;margin-bottom:0.25rem;font-weight:600}h5,h6{margin-top:0.5rem;margin-bottom:0.125rem;font-weight:600}h1,h2,h3,h4,h5,h6{word-break:break-word;hyphens:auto;-webkit-hyphens:auto}:not([contenteditable=true]) h1,:not([contenteditable=true]) h2,:not([contenteditable=true]) h3,:not([contenteditable=true]) h4,:not([contenteditable=true]) h5,:not([contenteditable=true]) h6{text-wrap:balance}[contenteditable=true] h1,[contenteditable=true] h2,[contenteditable=true] h3,[contenteditable=true] h4,[contenteditable=true] h5,[contenteditable=true] h6{text-wrap:initial}ul{list-style:none}ul li{position:relative;margin-left:0.75rem}ul li:before{content:\"\";position:absolute;left:-0.5rem;top:0.5rem;width:0.25rem;height:0.25rem;border-radius:50%;background-color:rgb(var(--contrast-700));display:block}ol{margin-top:0.25rem;padding-left:1rem}ul{margin-top:0.25rem;padding-left:0}ul ul,ul ol,ol ol,ol ul{margin-left:0}li{margin-bottom:0.25rem}code{font-family:ui-monospace, \"Cascadia Code\", \"Source Code Pro\", Menlo, Consolas, \"DejaVu Sans Mono\", monospace;font-size:0.8125rem;letter-spacing:-0.0125rem;color:rgb(var(--contrast-1300));-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;display:inline-block;border-radius:0.25rem;padding:0.03125rem 0.25rem;background-color:rgb(var(--contrast-600))}pre>code{display:block;margin:0.5rem 0;padding:0.5rem 0.75rem;overflow:auto;white-space:pre-wrap}:host(limel-markdown:not(.no-table-styles)) table{table-layout:auto;min-width:100%;border-collapse:collapse;border-spacing:0;background:transparent;margin:0.75rem 0}:host(limel-markdown:not(.no-table-styles)) tbody{border:1px solid rgb(var(--contrast-400));border-radius:0.25rem}:host(limel-markdown:not(.no-table-styles)) th,:host(limel-markdown:not(.no-table-styles)) td{text-align:left;vertical-align:top;transition:background-color 0.2s ease;font-size:0.875rem}:host(limel-markdown:not(.no-table-styles)) td{padding:0.5rem 0.375rem 0.75rem 0.375rem}:host(limel-markdown:not(.no-table-styles)) tr th{background-color:rgb(var(--contrast-400));padding:0.25rem 0.375rem;font-weight:normal}:host(limel-markdown:not(.no-table-styles)) tr th:only-child{text-align:center}:host(limel-markdown:not(.no-table-styles)) tbody tr:nth-child(odd) td{background-color:rgb(var(--contrast-200))}:host(limel-markdown:not(.no-table-styles)) tbody tr:hover td{background-color:rgb(var(--contrast-300))}table{display:block;box-sizing:border-box;overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}kbd{font-family:ui-monospace, \"Cascadia Code\", \"Source Code Pro\", Menlo, Consolas, \"DejaVu Sans Mono\", monospace;font-weight:600;color:rgb(var(--contrast-1100));background-color:rgb(var(--contrast-200));white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:normal;padding:0.125rem 0.5rem;margin:0 0.25rem;box-shadow:var(--button-shadow-normal), 0 0.03125rem 0.21875rem 0 rgba(var(--contrast-100), 0.5) inset;border-radius:0.125rem;border-style:solid;border-color:rgba(var(--contrast-600), 0.8);border-width:0 1px 0.125rem 1px}img{max-width:100%;border-radius:0.25rem}.image-wrapper{display:inline-flex;position:relative}.image-wrapper limel-linear-progress{position:absolute;inset:0.25rem auto auto 0.25rem;width:calc(100% - 0.5rem)}.image-wrapper img{transition:opacity 0.2s ease, scale 0.6s ease}.image-wrapper.state-failed,.image-wrapper.state-loading{background:url(\"data:image/svg+xml;charset=utf-8, <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8' style='fill-rule:evenodd;'><path fill='rgba(186,186,192,0.16)' d='M0 0h4v4H0zM4 4h4v4H4z'/></svg>\");background-size:0.5rem}.image-wrapper.state-failed img,.image-wrapper.state-loading img{opacity:0.3;scale:0.98}.image-wrapper::before{pointer-events:none;content:\"\";display:block;position:absolute;inset:0;border-radius:0.25rem;transition:border-color 0.4s ease, opacity 0.2s ease, box-shadow 0.6s ease;border:1px dashed transparent;opacity:0.2}.image-wrapper.state-failed img{filter:grayscale(0.8)}.image-wrapper.state-failed:before{opacity:0.8;box-shadow:var(--shadow-error-state)}.image-wrapper:hover::before{opacity:0.8;box-shadow:var(--shadow-depth-8)}.image-wrapper:has(.resize-handle[aria-grabbed=true])::before{border-color:var(--mdc-theme-primary);opacity:0.8;box-shadow:var(--shadow-depth-16), var(--shadow-depth-8)}.resize-handle{transition:color var(--limel-clickable-transition-speed, 0.4s) ease, background-color var(--limel-clickable-transition-speed, 0.4s) ease, box-shadow var(--limel-clickable-transform-speed, 0.4s) ease, transform var(--limel-clickable-transform-speed, 0.4s) var(--limel-clickable-transform-timing-function, ease);cursor:pointer;color:var(--mdc-theme-on-surface);background-color:rgb(var(--contrast-900));box-shadow:var(--button-shadow-normal);cursor:nwse-resize;position:absolute;display:flex;align-items:center;justify-content:center;width:0.5rem;height:0.5rem;border-radius:50%;opacity:0.6}.resize-handle:hover,.resize-handle:focus,.resize-handle:focus-visible{will-change:color, background-color, box-shadow, transform}.resize-handle:hover{transform:translate3d(0, -0.04rem, 0);color:var(--mdc-theme-on-surface);background-color:var(--lime-elevated-surface-background-color);box-shadow:var(--button-shadow-hovered)}.resize-handle:active{--limel-clickable-transform-timing-function:cubic-bezier(\n 0.83,\n -0.15,\n 0.49,\n 1.16\n );transform:translate3d(0, 0.05rem, 0);box-shadow:var(--button-shadow-pressed)}.resize-handle:hover,.resize-handle:active{--limel-clickable-transition-speed:0.2s;--limel-clickable-transform-speed:0.16s}.resize-handle:focus{outline:none}.resize-handle:focus-visible{outline:none;box-shadow:var(--shadow-depth-8-focused)}.resize-handle.top-left{left:-0.25rem;top:-0.25rem;translate:-50%, -50%}.resize-handle.bottom-right{right:-0.25rem;bottom:-0.25rem;translate:50%, 50%}.resize-wrapper:has(.resize-handle[aria-grabbed=true]) .resize-handle,.resize-wrapper:hover .resize-handle,.resize-handle:hover,.resize-handle:focus-visible{opacity:1}.resize-handle[aria-grabbed=true],.resize-handle:hover,.resize-handle:focus-visible{opacity:1;background-color:var(--mdc-theme-primary)}.resize-handle:hover,.resize-handle[aria-grabbed=true]{scale:1.4}.resize-handle:hover:before,.resize-handle[aria-grabbed=true]:before{background-color:rgb(var(--color-white))}.resize-handle:before{content:\"\";display:block;position:absolute;inset:0;margin:auto;border-radius:50%;width:0.25rem;height:0.25rem;background-color:rgb(var(--contrast-100))}:host(limel-prosemirror-adapter){display:flex;flex-direction:column}:host(limel-prosemirror-adapter) .toolbar{order:1}:host(limel-prosemirror-adapter) div#editor{order:2;height:100%;flex-grow:1}:host(limel-prosemirror-adapter) div[contenteditable=true]{height:100%}*{box-sizing:border-box}:host(limel-prosemirror-adapter:hover) .toolbar,:host(limel-prosemirror-adapter:focus-within) .toolbar{will-change:grid-template-rows}:host(limel-prosemirror-adapter:hover) limel-action-bar,:host(limel-prosemirror-adapter:focus-within) limel-action-bar{will-change:opacity, padding}.ProseMirror-menubar-wrapper{display:grid;grid-template-rows:auto 1fr}.ProseMirror-textblock-dropdown{min-width:3em}.ProseMirror-tooltip .ProseMirror-menu{width:-webkit-fit-content;width:fit-content;white-space:pre}.toolbar{--action-bar-border-radius:0.25rem;border-radius:var(--action-bar-border-radius);flex-shrink:0;position:sticky;z-index:1;top:0;width:100%;display:grid;grid-template-rows:var(--limel-prosemirror-adapter-toolbar-grid-template-rows);transition-property:grid-template-rows;transition-duration:var(--limel-prosemirror-adapter-toolbar-grid-template-rows-transition-duration);transition-timing-function:var(--limel-prosemirror-adapter-toolbar-transition-timing-function);background-color:rgba(var(--contrast-200), 0.5);backdrop-filter:blur(0.5rem);-webkit-backdrop-filter:blur(0.5rem)}limel-action-bar{min-width:0;transition-property:padding, opacity;transition-duration:var(--limel-prosemirror-adapter-toolbar-grid-template-rows-transition-duration);transition-timing-function:var(--limel-prosemirror-adapter-toolbar-transition-timing-function);opacity:var(--limel-prosemirror-adapter-toolbar-opacity);padding:var(--limel-prosemirror-adapter-action-bar-padding-top-bottom, 0.125rem) 0.25rem;background-color:transparent;overflow:hidden}.ProseMirror{position:relative;word-wrap:break-word;white-space:pre-wrap;white-space:break-spaces;-webkit-font-variant-ligatures:none;font-variant-ligatures:none;font-feature-settings:\"liga\" 0;padding:var(--limel-text-editor-padding)}.ProseMirror [draggable][contenteditable=false]{user-select:text}.ProseMirror:focus-visible{outline:none}.ProseMirror-hideselection{caret-color:transparent}.ProseMirror-hideselection *::selection{background:transparent}.ProseMirror-hideselection *::-moz-selection{background:transparent}.ProseMirror-selectednode{outline:0.125rem solid rgb(var(--color-sky-light))}li.ProseMirror-selectednode{outline:none}li.ProseMirror-selectednode:after{content:\"\";position:absolute;left:-2rem;right:-0.125rem;top:-0.125rem;bottom:-0.125rem;border:0.125rem solid rgb(var(--color-sky-light));pointer-events:none}img.ProseMirror-separator{display:inline !important;border:none !important;margin:0 !important}limel-portal{width:25rem}";
28320
28398
 
28321
28399
  const DEBOUNCE_TIMEOUT = 300;
@@ -28325,7 +28403,9 @@ const ProsemirrorAdapter = class {
28325
28403
  this.change = createEvent(this, "change", 7);
28326
28404
  this.imagePasted = createEvent(this, "imagePasted", 7);
28327
28405
  this.imageRemoved = createEvent(this, "imageRemoved", 7);
28406
+ this.metadataChange = createEvent(this, "metadataChange", 7);
28328
28407
  this.changeWaiting = false;
28408
+ this.metadata = { images: [], links: [] };
28329
28409
  /**
28330
28410
  * Used to stop change event emitting as result of getting updated value from consumer
28331
28411
  */
@@ -28362,6 +28442,8 @@ const ProsemirrorAdapter = class {
28362
28442
  if (content === this.lastEmittedValue) {
28363
28443
  return;
28364
28444
  }
28445
+ const metadata = getMetadataFromDoc(newState.doc);
28446
+ this.metadataEmitter(metadata);
28365
28447
  this.lastEmittedValue = content;
28366
28448
  this.changeWaiting = true;
28367
28449
  this.changeEmitter(content);
@@ -28553,7 +28635,7 @@ const ProsemirrorAdapter = class {
28553
28635
  keymap(this.menuCommandFactory.buildKeymap()),
28554
28636
  createTriggerPlugin(this.triggerCharacters, this.contentConverter),
28555
28637
  createLinkPlugin(this.handleNewLinkSelection),
28556
- createImageInserterPlugin(this.imagePasted.emit, this.imageRemoved.emit),
28638
+ createImageInserterPlugin(this.imagePasted.emit),
28557
28639
  createImageViewPlugin(this.language),
28558
28640
  createMenuStateTrackingPlugin(editorMenuTypesArray, this.menuCommandFactory, this.updateActiveActionBarItems),
28559
28641
  createActionBarInteractionPlugin(this.menuCommandFactory),
@@ -28571,8 +28653,24 @@ const ProsemirrorAdapter = class {
28571
28653
  const tr = this.view.state.tr;
28572
28654
  tr.replaceWith(0, tr.doc.content.size, prosemirrorDoc.content);
28573
28655
  this.view.dispatch(tr);
28656
+ const metadata = getMetadataFromDoc(this.view.state.doc);
28657
+ this.metadataEmitter(metadata);
28574
28658
  this.suppressChangeEvent = false;
28575
28659
  }
28660
+ metadataEmitter(metadata) {
28661
+ if (hasMetadataChanged(this.metadata, metadata)) {
28662
+ this.removeImagesFromCache(this.metadata, metadata);
28663
+ this.metadata = metadata;
28664
+ this.metadataChange.emit(metadata);
28665
+ }
28666
+ }
28667
+ removeImagesFromCache(oldMetadata, newMetadata) {
28668
+ const removedImages = oldMetadata.images.filter((oldImage) => !newMetadata.images.some((newImage) => newImage.fileInfoId === oldImage.fileInfoId));
28669
+ removedImages.forEach((image) => {
28670
+ imageCache.delete(image.fileInfoId);
28671
+ this.imageRemoved.emit(image);
28672
+ });
28673
+ }
28576
28674
  static get delegatesFocus() { return true; }
28577
28675
  get host() { return getElement(this); }
28578
28676
  static get watchers() { return {