native-document 1.0.187 → 1.0.188

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "native-document",
3
- "version": "1.0.187",
3
+ "version": "1.0.188",
4
4
  "description": "A reactive JavaScript framework that preserves native DOM simplicity without sacrificing modern features",
5
5
  "author": "AfroCodeur <https://github.com/afrocodeur>",
6
6
  "license": "MIT",
@@ -0,0 +1,37 @@
1
+ import BaseComponent from '../BaseComponent';
2
+ import Button from './Button';
3
+
4
+
5
+ export default function CopyButton(content, props){
6
+
7
+ if(!(this instanceof CopyButton)) {
8
+ return new CopyButton(content, props);
9
+ }
10
+
11
+ Button.call(this, content, props);
12
+
13
+ Object.assign(this.$description, {
14
+ target: null,
15
+ content,
16
+ props,
17
+ });
18
+
19
+ };
20
+
21
+ BaseComponent.extends(CopyButton, Button);
22
+
23
+ CopyButton.defaultTemplate = null;
24
+ CopyButton.use = function (render){
25
+ CopyButton.defaultTemplate = render;
26
+ };
27
+
28
+ /**
29
+ *
30
+ * @param {Observable} $observable
31
+ * @returns {CopyButton}
32
+ */
33
+ CopyButton.prototype.from = function($observable) {
34
+ this.$description.target = $observable;
35
+ return this;
36
+ };
37
+
@@ -0,0 +1,32 @@
1
+ import Button from './Button';
2
+ import BaseComponent from '../BaseComponent';
3
+
4
+
5
+ export default function PasteButton(content, props) {
6
+
7
+ if(!(this instanceof PasteButton)) {
8
+ return new PasteButton(content, props);
9
+ }
10
+
11
+ Button.call(this, content, props);
12
+
13
+ Object.assign(this.$description, {
14
+ content,
15
+ props,
16
+ target: null,
17
+ });
18
+ }
19
+
20
+ BaseComponent.extends(PasteButton, Button);
21
+
22
+
23
+ PasteButton.defaultTemplate = null;
24
+ PasteButton.use = function (render){
25
+ PasteButton.defaultTemplate = render;
26
+ };
27
+
28
+
29
+ PasteButton.prototype.into = function($observable) {
30
+ this.$description.target = $observable;
31
+ return this;
32
+ };
@@ -0,0 +1,5 @@
1
+ import Button from './Button';
2
+
3
+ export default function ResetButton(content, props) {
4
+ return Button(content, props).type('reset');
5
+ }
@@ -0,0 +1,5 @@
1
+ import Button from './Button';
2
+
3
+ export default function SubmitButton(content, props){
4
+ return Button(content, props).type('submit');
5
+ }
@@ -1,5 +1,13 @@
1
1
  import Button from './Button';
2
+ import SubmitButton from './SubmitButton';
3
+ import ResetButton from './ResetButton';
4
+ import PasteButton from './PasteButton';
5
+ import CopyButton from './CopyButton';
2
6
 
3
7
  export {
4
8
  Button,
9
+ SubmitButton,
10
+ ResetButton,
11
+ PasteButton,
12
+ CopyButton,
5
13
  };
@@ -53,10 +53,8 @@ export interface ButtonInterface extends BaseComponent {
53
53
  export declare function Button(label: ValidChild, props?: Record<string, unknown>): ButtonInterface;
54
54
  export declare namespace Button {
55
55
 
56
-
57
56
  function use(template: (description: ButtonDescription, instance: ButtonInterface) => ValidChild): void;
58
57
  function preset(name: string, callback: (instance: ButtonInterface) => ButtonInterface): void;
59
58
  function presets(presets: Record<string, (instance: ButtonInterface) => ButtonInterface>): void;
60
59
 
61
-
62
60
  }
@@ -0,0 +1,16 @@
1
+ import {ButtonInterface} from "./Button";
2
+ import {ObservableItem} from "../../../../types/observable";
3
+ import {ValidChild} from "../../../../types/elements";
4
+
5
+
6
+ export interface CopyButtonInterface extends ButtonInterface{
7
+
8
+ from($observable: ObservableItem): this;
9
+
10
+ }
11
+ export declare function CopyButton(label: ValidChild, props?: Record<string, unknown>): CopyButtonInterface;
12
+ export declare namespace CopyButton {
13
+
14
+ function use(template: (description: ButtonInterface, instance: ButtonInterface) => ValidChild): void;
15
+
16
+ }
@@ -0,0 +1,16 @@
1
+ import {ButtonDescription, ButtonInterface} from "./Button";
2
+ import {ObservableItem} from "../../../../types/observable";
3
+ import type {ValidChild} from "../../../../types/elements";
4
+
5
+
6
+ export interface PasteButtonInterface extends ButtonInterface{
7
+
8
+ into($observable: ObservableItem): this;
9
+
10
+ }
11
+ export declare function PasteButton(label: ValidChild, props?: Record<string, unknown>): PasteButtonInterface;
12
+ export declare namespace PasteButton {
13
+
14
+ function use(template: (description: ButtonDescription, instance: ButtonInterface) => ValidChild): void;
15
+
16
+ }
@@ -0,0 +1,6 @@
1
+ import {ButtonInterface} from "./Button";
2
+
3
+
4
+ export interface ResetButton extends ButtonInterface {
5
+
6
+ }
@@ -0,0 +1,6 @@
1
+ import {ButtonInterface} from "./Button";
2
+
3
+
4
+ export interface SubmitButton extends ButtonInterface {
5
+
6
+ }
@@ -39,6 +39,7 @@ export default function RadioField(name, props = {}) {
39
39
  options: [],
40
40
  layout: 'vertical',
41
41
  checked: false,
42
+ renderItem: null,
42
43
  });
43
44
  }
44
45
 
@@ -142,4 +143,13 @@ RadioField.prototype.vertical = function() {
142
143
  RadioField.prototype.grid = function() {
143
144
  this.$description.layout = 'grid';
144
145
  return this;
146
+ };
147
+
148
+ /**
149
+ * @param {Function} renderFn
150
+ * @returns {RadioField}
151
+ */
152
+ RadioField.prototype.renderItem = function(renderFn) {
153
+ this.$description.renderItem = renderFn;
154
+ return this;
145
155
  };
@@ -2,6 +2,7 @@ import type { ValidChild } from '../../../../../types/elements';
2
2
  import type { ObservableItem } from '../../../../../types/observable';
3
3
  import type { GlobalAttributes } from '../../../../../types/globals';
4
4
  import type { FieldInterface } from '../Field';
5
+ import {HTMLInputElement} from "happy-dom";
5
6
 
6
7
  interface RadioOption {
7
8
  value: unknown;
@@ -35,6 +36,7 @@ export interface RadioFieldInterface extends Omit<FieldInterface, 'render' | 'mo
35
36
  horizontal(): this;
36
37
  vertical(): this;
37
38
  grid(): this;
39
+ renderItem(item: (input: HTMLInputElement, data: RadioOption) => ValidChild): this;
38
40
  }
39
41
 
40
42
 
@@ -31,6 +31,10 @@ export type { BreadCrumb, BreadCrumbInterface, BreadCrumbDescription } from './b
31
31
 
32
32
  // --- Button ------------------------------------------------------------------
33
33
  export type { Button, ButtonInterface, ButtonDescription } from './button/types/Button';
34
+ export type { CopyButton } from './button/types/CopyButton';
35
+ export type { PasteButton } from './button/types/PasteButton';
36
+ export type { SubmitButton } from './button/types/SubmitButton';
37
+ export type { ResetButton } from './button/types/ResetButton';
34
38
 
35
39
  // --- Card --------------------------------------------------------------------
36
40
  export type { Card, CardInterface, CardDescription } from './card/types/Card';
@@ -363,20 +363,24 @@ DataTable.prototype.onSort = function(handler) {
363
363
  // ---------------------------------------------
364
364
 
365
365
  /**
366
- * @param {*} [enabled]
366
+ * @param {boolean} [enabled]
367
+ * @param {Observable} [model]
367
368
  * @returns {this}
368
369
  */
369
- DataTable.prototype.searchable = function(enabled = true) {
370
+ DataTable.prototype.searchable = function(enabled = true, model = null) {
370
371
  this.$description.searchable = enabled;
372
+ this.$description.$search = model;
371
373
  return this;
372
374
  };
373
375
 
374
376
  /**
375
- * @param {*} [enabled]
377
+ * @param {boolean} [enabled]
378
+ * @param {Record<string, *>?} filters
376
379
  * @returns {this}
377
380
  */
378
- DataTable.prototype.filterable = function(enabled = true) {
381
+ DataTable.prototype.filterable = function(enabled = true, filters = null) {
379
382
  this.$description.filterable = enabled;
383
+ this.$description.defaultFilter = filters;
380
384
  return this;
381
385
  };
382
386
 
@@ -278,6 +278,7 @@ ObservableArray.prototype.populateAndRender = function(iteration, callback) {
278
278
  * The filtered array updates automatically when source data or predicates change.
279
279
  *
280
280
  * @param {Object} predicates - Object mapping property names to filter conditions or functions
281
+ * @param {Observable[]?} dependencies - dependencies list when predicates is a function
281
282
  * @returns {ObservableArray} A new observable array containing filtered items
282
283
  * @example
283
284
  * const users = Observable.array([
@@ -287,9 +288,9 @@ ObservableArray.prototype.populateAndRender = function(iteration, callback) {
287
288
  *
288
289
  * const adults = users.where({ age: (val) => val >= 18 });
289
290
  */
290
- ObservableArray.prototype.where = function(predicates) {
291
+ ObservableArray.prototype.where = function(predicates, dependencies = null) {
291
292
  if(typeof predicates === 'function') {
292
- predicates = { _: predicates };
293
+ predicates = { _: predicates, dependencies };
293
294
  }
294
295
  const sourceArray = this;
295
296
  const observableDependencies = [sourceArray];
@@ -322,7 +323,10 @@ ObservableArray.prototype.where = function(predicates) {
322
323
  if(key === '_') {
323
324
  if (!callback(item)) return false;
324
325
  } else {
325
- if (!callback(item[key])) return false;
326
+ const valueSource = item[key];
327
+ if (!callback(valueSource?.__$Observable ? valueSource.val() : valueSource)) {
328
+ return false;
329
+ }
326
330
  }
327
331
  }
328
332
  return true;
@@ -1,4 +1,5 @@
1
1
  import {trim} from '../core/utils/helpers.js';
2
+ import {Observable} from '../core/data/Observable';
2
3
 
3
4
  export const RouteParamPatterns = {
4
5
  id: '[0-9]+',
@@ -112,16 +113,26 @@ export function Route($path, $component, $options = {}) {
112
113
  /**
113
114
  * @param {{params: ?Object, query: ?Object, basePath: ?string}} configs
114
115
  */
115
- this.url = function(configs) {
116
+ this.url = function(configs = {}) {
116
117
  const path = $path.replace(/\{(.*?)}/ig, (block, definition) => {
117
118
  const description = paramsExtractor(definition);
118
119
  if(configs.params && configs.params[description.name]) {
119
- return configs.params[description.name];
120
+ const value = configs.params[description.name];
121
+ return value?.__$Observable ? value.val() : value;
120
122
  }
121
123
  throw new Error(`Missing parameter '${description.name}'`);
122
124
  });
123
125
 
124
- const queryString = (typeof configs.query === 'object') ? (new URLSearchParams(configs.query)).toString() : null;
126
+ let queries = null;
127
+ if(typeof configs.query === 'object') {
128
+ queries = {};
129
+ for(const property in configs.query) {
130
+ const value = configs.query[property];
131
+ queries[property] = value?.__$Observable ? value.val() : value;
132
+ }
133
+ }
134
+
135
+ const queryString = (queries) ? (new URLSearchParams(queries)).toString() : null;
125
136
  return (configs.basePath ? configs.basePath : '') + (queryString ? `${path}?${queryString}` : path);
126
137
  };
127
138
  }
@@ -0,0 +1,13 @@
1
+ import ButtonRender from './ButtonRender';
2
+
3
+
4
+ export default function CopyButtonRender($desc, instance) {
5
+
6
+ return ButtonRender($desc, instance).onClick(() => {
7
+ if(!$desc.target) {
8
+ return;
9
+ }
10
+
11
+ navigator.clipboard.writeText($desc.target.val());
12
+ });
13
+ }
@@ -0,0 +1,14 @@
1
+ import {ButtonRender} from '../../index';
2
+
3
+
4
+ export default function PasteButtonRender($desc, instance) {
5
+
6
+ return ButtonRender($desc, instance).onClick(() => {
7
+ if(!$desc.target) {
8
+ return;
9
+ }
10
+ navigator.clipboard.readText().then(text => {
11
+ $desc.target.set(text);
12
+ });
13
+ });
14
+ }
@@ -47,7 +47,7 @@ const buildOptions = ($desc, instance) => {
47
47
  instance.validate();
48
48
  };
49
49
 
50
- const buildOption = (option) => {
50
+ const buildOption = ($desc, option) => {
51
51
  const optValue = option.value ?? option;
52
52
  const optLabel = option.label ?? option;
53
53
  const optId = ($desc.id || $desc.name) + '-' + optValue;
@@ -64,6 +64,10 @@ const buildOptions = ($desc, instance) => {
64
64
 
65
65
  input.nd.onChange(() => onSelect(optValue));
66
66
 
67
+ if($desc.renderItem) {
68
+ return Div({class: 'field-radio-wrapper'}, $desc.renderItem(input, option));
69
+ }
70
+
67
71
  return Div({class: 'field-radio-wrapper'}, [
68
72
  input,
69
73
  Label({class: 'field-radio-label', for: optId}, optLabel),
@@ -71,11 +75,12 @@ const buildOptions = ($desc, instance) => {
71
75
  };
72
76
 
73
77
  const isRequired = $desc.rules?.some(rule => rule.fn?.name === 'required');
78
+ const optionBuilder = buildOption.bind(null, $desc);
74
79
  return Div({
75
80
  class: 'field-radio-group is-' + ($desc.layout || 'vertical'),
76
81
  // [a11y] role=radiogroup, aria-required
77
82
  role: 'radiogroup',
78
83
  ...( isRequired ? { 'aria-required': 'true' } : {} ),
79
84
  ...($desc.elementsProps.wrapper || {}),
80
- }, ForEachArray($options, buildOption));
85
+ }, ForEachArray($options, optionBuilder));
81
86
  };
package/src/ui/index.js CHANGED
@@ -6,6 +6,8 @@ export { default as DividerRender } from './components/divider/DividerRender';
6
6
  export { default as SkeletonRender } from './components/skeleton/SkeletonRender';
7
7
  export { default as ProgressRender } from './components/progress/ProgressRender';
8
8
  export { default as ButtonRender } from './components/button/ButtonRender';
9
+ export { default as CopyButtonRender } from './components/button/CopyButtonRender';
10
+ export { default as PasteButtonRender } from './components/button/PasteButtonRender';
9
11
  export { default as AlertRender } from './components/alert/AlertRender';
10
12
  export { default as ToastRender } from './components/toast/ToastRender';
11
13
  export { default as PopoverRender } from './components/popover/PopoverRender';