@seedgrid/fe-components 2026.8.4 → 2026.8.6
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/dist/ai/seedgrid-components.manifest.json +223 -0
- package/dist/generated/compiledStyles.d.ts +1 -1
- package/dist/generated/compiledStyles.d.ts.map +1 -1
- package/dist/generated/compiledStyles.js +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/inputs/SgYearPartSelector.d.ts +38 -0
- package/dist/inputs/SgYearPartSelector.d.ts.map +1 -0
- package/dist/inputs/SgYearPartSelector.js +86 -0
- package/dist/inputs/SgYearPartSelector.meta.d.ts +4 -0
- package/dist/inputs/SgYearPartSelector.meta.d.ts.map +1 -0
- package/dist/inputs/SgYearPartSelector.meta.js +93 -0
- package/dist/inputs/yearPart.d.ts +71 -0
- package/dist/inputs/yearPart.d.ts.map +1 -0
- package/dist/inputs/yearPart.js +123 -0
- package/dist/sandbox.cjs +34 -34
- package/dist/style.css +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export const sgMeta = {
|
|
2
|
+
version: "0.1",
|
|
3
|
+
componentId: "form.input.yearPartSelector",
|
|
4
|
+
package: "@seedgrid/fe-components",
|
|
5
|
+
exportName: "SgYearPartSelector",
|
|
6
|
+
slug: "sg-year-part-selector",
|
|
7
|
+
displayName: "SgYearPartSelector",
|
|
8
|
+
category: "input",
|
|
9
|
+
subcategory: "period",
|
|
10
|
+
description: "Seletor de recorte de ano: o usuario escolhe ANO + RECORTE (semestre, trimestre ou bimestre) + FATIA, e o componente resolve para um intervalo real e fechado de datas. E' o irmao ABSOLUTO do SgPeriodSelector: aquele resolve presets RELATIVOS a hoje (\"este semestre\"), este resolve um recorte fixo de um ano civil informado (\"o 1o semestre DE 2024\"), que nao muda de significado com a passagem do tempo.",
|
|
11
|
+
tags: ["form", "period", "year", "semester", "quarter", "bimester", "date-range", "filter", "report", "rhf"],
|
|
12
|
+
capabilities: [
|
|
13
|
+
"single-selection",
|
|
14
|
+
"date-resolution",
|
|
15
|
+
"absolute-period",
|
|
16
|
+
"year-range-limits",
|
|
17
|
+
"kind-filtering",
|
|
18
|
+
"part-clamping",
|
|
19
|
+
"leap-year-safe"
|
|
20
|
+
],
|
|
21
|
+
fieldSemantics: ["dateRange", "periodFilter", "fiscalPeriod", "structuredChoice", "year"],
|
|
22
|
+
props: [
|
|
23
|
+
{ name: "id", type: "string", default: "sg-year-part-selector", description: "Prefixo dos ids dos tres controles internos (ano, recorte, fatia). Nao e' o id de um campo unico: o componente monta tres.", semanticRole: "data", bindable: false },
|
|
24
|
+
{ name: "label", type: "string", description: "Rotulo exibido ao usuario.", semanticRole: "label", bindable: true },
|
|
25
|
+
{ name: "value", type: "YearPartValue", description: "Recorte selecionado no modo controlado: { year, kind, part }, com part em base 1 (1..2 no semestre, 1..4 no trimestre, 1..6 no bimestre).", semanticRole: "value", bindable: true },
|
|
26
|
+
{ name: "onChange", type: "(resolved: ResolvedYearPart) => void", description: "Callback com o recorte ja resolvido: value, label e o intervalo fechado startDate/endDate. As datas NUNCA vem nulas, diferente do ResolvedPeriod do SgPeriodSelector.", semanticRole: "event", bindable: false },
|
|
27
|
+
{ name: "allowedKinds", type: "YearPartKind[]", default: ["SEMESTER", "QUARTER", "BIMESTER"], description: "Recortes oferecidos no combo. Reduza a lista quando o dominio so' aceita um deles (fechamento trimestral, por exemplo); com um unico item o combo de recorte deixa de fazer sentido na tela.", semanticRole: "behavior", bindable: true },
|
|
28
|
+
{ name: "minYear", type: "number", default: "ano corrente - 30", description: "Primeiro ano oferecido na lista de anos.", semanticRole: "behavior", bindable: true },
|
|
29
|
+
{ name: "maxYear", type: "number", default: "ano corrente + 10", description: "Ultimo ano oferecido na lista de anos.", semanticRole: "behavior", bindable: true },
|
|
30
|
+
{ name: "locale", type: "string", default: "pt-BR", description: "Locale dos rotulos de recorte e fatia. A sigla entre parenteses acompanha o idioma: Q1..Q4 em pt-BR e en-US, T1..T4 em es, fr e pt-PT; bimestre nao tem sigla e sai sem parenteses.", semanticRole: "behavior", bindable: true },
|
|
31
|
+
{ name: "disabled", type: "boolean", default: false, description: "Desabilita os tres combos (ano, recorte e fatia).", semanticRole: "behavior", bindable: true },
|
|
32
|
+
{ name: "required", type: "boolean", default: false, description: "Marca o campo como obrigatorio.", semanticRole: "validation", bindable: true },
|
|
33
|
+
{ name: "className", type: "string", description: "Classes extras aplicadas ao container do campo.", semanticRole: "appearance", bindable: false }
|
|
34
|
+
],
|
|
35
|
+
states: ["default", "focused", "open", "disabled", "required", "error"],
|
|
36
|
+
showcase: {
|
|
37
|
+
route: "/components/sg-year-part-selector",
|
|
38
|
+
hasPlayground: true,
|
|
39
|
+
hasPropsTable: true
|
|
40
|
+
},
|
|
41
|
+
sdui: {
|
|
42
|
+
rendererType: "field.yearPartSelector",
|
|
43
|
+
acceptsDataBinding: true,
|
|
44
|
+
defaultProps: {
|
|
45
|
+
allowedKinds: ["SEMESTER", "QUARTER", "BIMESTER"],
|
|
46
|
+
locale: "pt-BR",
|
|
47
|
+
disabled: false,
|
|
48
|
+
required: false
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
export const aiHints = {
|
|
53
|
+
version: "0.1",
|
|
54
|
+
preferredUseCases: [
|
|
55
|
+
"Filtro de relatorio em que o periodo e' um recorte ABSOLUTO de um ano informado: \"1o semestre de 2024\", \"Q3 de 2023\", \"4o bimestre de 2025\".",
|
|
56
|
+
"Comparacao entre anos: mesma fatia, ano diferente (Q1/2024 contra Q1/2025).",
|
|
57
|
+
"Fechamentos periodicos (contabil, fiscal, apuracao de metas) que sempre caem em semestre, trimestre ou bimestre cheios.",
|
|
58
|
+
"Consultas a periodos historicos, em que o usuario sabe o ano e a fatia mas nao a data exata de inicio e fim."
|
|
59
|
+
],
|
|
60
|
+
avoidUseCases: [
|
|
61
|
+
"Periodo relativo a hoje (\"este mes\", \"ultimo trimestre\", \"ultimos 30 dias\"); use SgPeriodSelector, que reavalia a regra a cada abertura da tela.",
|
|
62
|
+
"Intervalo arbitrario que nao respeita as bordas do recorte (05/03 a 17/08); use um date range ou o modo customizado do SgPeriodSelector.",
|
|
63
|
+
"Recorte mensal isolado ou semana; este componente so' fatia o ano em 2, 4 ou 6 partes iguais.",
|
|
64
|
+
"Selecao de uma unica data; prefira SgInputDate.",
|
|
65
|
+
"Selecao apenas do ano, sem fatia; um combo simples resolve."
|
|
66
|
+
],
|
|
67
|
+
synonyms: [
|
|
68
|
+
"year part selector",
|
|
69
|
+
"seletor de recorte de ano",
|
|
70
|
+
"seletor de semestre",
|
|
71
|
+
"seletor de trimestre",
|
|
72
|
+
"seletor de bimestre",
|
|
73
|
+
"quarter picker",
|
|
74
|
+
"semester picker",
|
|
75
|
+
"half-year selector",
|
|
76
|
+
"fiscal period selector",
|
|
77
|
+
"periodo do ano"
|
|
78
|
+
],
|
|
79
|
+
relatedEntityFields: ["ano", "exercicio", "semestre", "trimestre", "bimestre", "competencia", "periodoApuracao", "dataInicio", "dataFim"],
|
|
80
|
+
compositionHints: [
|
|
81
|
+
"Usar como filtro superior de SgDatatable e de graficos comparativos entre anos.",
|
|
82
|
+
"Colocar dentro de SgToolBar ou de um SgPanel de filtros, ao lado dos demais recortes.",
|
|
83
|
+
"Quando a tela precisa dos dois modos, ofereca SgPeriodSelector para o relativo e SgYearPartSelector para o absoluto; os dois entregam startDate/endDate no mesmo formato, entao o consumidor trata os dois com o mesmo codigo.",
|
|
84
|
+
"Ao trocar o recorte, a fatia fora de faixa cai para a primeira (clampYearPart); nao e' preciso tratar isso no consumidor."
|
|
85
|
+
],
|
|
86
|
+
rankingSignals: {
|
|
87
|
+
freeText: 0,
|
|
88
|
+
structuredChoice: 0.9,
|
|
89
|
+
date: 0.9,
|
|
90
|
+
number: 0.3,
|
|
91
|
+
denseLayout: 0.6
|
|
92
|
+
}
|
|
93
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recorte de um ano civil em fatias de tamanho igual: semestre (2), trimestre (4) e bimestre (6).
|
|
3
|
+
*
|
|
4
|
+
* Existe para o mesmo fim do SgPeriodSelector — resolver uma REGRA temporal para um intervalo real
|
|
5
|
+
* de datas — mas para a pergunta que ele nao responde: "o 1o semestre DE 2024", e nao "este
|
|
6
|
+
* semestre". Preset e' relativo a hoje; aqui o usuario escolhe ano e fatia.
|
|
7
|
+
*
|
|
8
|
+
* Modulo separado do componente porque isto e' aritmetica de calendario pura: da' para testar sem
|
|
9
|
+
* DOM (ver tests/year-part-resolver.test.mjs), que e' onde os erros de virada de mes/ano moram.
|
|
10
|
+
*/
|
|
11
|
+
export declare enum YearPartKind {
|
|
12
|
+
SEMESTER = "SEMESTER",
|
|
13
|
+
QUARTER = "QUARTER",
|
|
14
|
+
BIMESTER = "BIMESTER"
|
|
15
|
+
}
|
|
16
|
+
export type YearPartValue = {
|
|
17
|
+
year: number;
|
|
18
|
+
kind: YearPartKind;
|
|
19
|
+
/** Fatia dentro do ano, base 1: 1..2 no semestre, 1..4 no trimestre, 1..6 no bimestre. */
|
|
20
|
+
part: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Espelha o formato de ResolvedPeriod (do SgPeriodSelector) de proposito: quem consome os dois
|
|
24
|
+
* seletores — o filtro de relatorio, por exemplo — trata os dois com o mesmo codigo. A diferenca e'
|
|
25
|
+
* que aqui as datas NUNCA sao nulas: todo recorte de ano resolve para um intervalo fechado.
|
|
26
|
+
*/
|
|
27
|
+
export type ResolvedYearPart = {
|
|
28
|
+
value: YearPartValue;
|
|
29
|
+
label: string;
|
|
30
|
+
startDate: Date;
|
|
31
|
+
endDate: Date;
|
|
32
|
+
};
|
|
33
|
+
/** Quantas fatias cabem no ano para este recorte. */
|
|
34
|
+
export declare function yearPartCount(kind: YearPartKind): number;
|
|
35
|
+
/** Quantos meses tem cada fatia deste recorte: 6, 3 ou 2. */
|
|
36
|
+
export declare function yearPartMonths(kind: YearPartKind): number;
|
|
37
|
+
/** Nome do recorte no locale pedido ("Trimestre", "Quarter"). */
|
|
38
|
+
export declare function yearPartKindLabel(kind: YearPartKind, locale?: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Rotulo de uma fatia: "Trimestre 1 (Q1)", "Semestre 2 (S2)", "Bimestre 3".
|
|
41
|
+
*
|
|
42
|
+
* O numero vem DEPOIS do nome porque a forma ordinal ("1o trimestre") exigiria o indicador
|
|
43
|
+
* ordinal, que esta' fora do ASCII que esta familia de componentes usa nos rotulos.
|
|
44
|
+
*/
|
|
45
|
+
export declare function yearPartLabel(kind: YearPartKind, part: number, locale?: string): string;
|
|
46
|
+
/** Opcoes prontas para o combo da fatia, ja no locale pedido. */
|
|
47
|
+
export declare function yearPartOptions(kind: YearPartKind, locale?: string): {
|
|
48
|
+
value: number;
|
|
49
|
+
label: string;
|
|
50
|
+
}[];
|
|
51
|
+
/** A fatia existe neste recorte? */
|
|
52
|
+
export declare function isValidYearPart(kind: YearPartKind, part: number): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Ao trocar o recorte, a fatia escolhida pode nao existir mais (estava no Q4 e virou semestre, que
|
|
55
|
+
* so' tem 2). Mantem a fatia quando ela couber, e cai na primeira quando nao couber — em vez de
|
|
56
|
+
* deixar um valor selecionado sem opcao correspondente na tela.
|
|
57
|
+
*/
|
|
58
|
+
export declare function clampYearPart(kind: YearPartKind, part: number): number;
|
|
59
|
+
/**
|
|
60
|
+
* Resolve o recorte para o intervalo fechado de datas.
|
|
61
|
+
*
|
|
62
|
+
* O ultimo dia sai de `new Date(ano, primeiroMesDaProximaFatia, 0)`: dia zero e' o ultimo dia do
|
|
63
|
+
* mes anterior, entao fevereiro devolve 29 em ano bissexto sem nenhuma tabela de dias por mes.
|
|
64
|
+
*
|
|
65
|
+
* Lanca quando a fatia nao existe no recorte — numero errado aqui vira intervalo errado no
|
|
66
|
+
* relatorio, e intervalo errado com cara de certo e' pior que erro na cara.
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveYearPart(value: YearPartValue, locale?: string): ResolvedYearPart;
|
|
69
|
+
/** Em que fatia do recorte esta data cai. Util para posicionar o seletor no periodo corrente. */
|
|
70
|
+
export declare function yearPartOf(date: Date, kind: YearPartKind): YearPartValue;
|
|
71
|
+
//# sourceMappingURL=yearPart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yearPart.d.ts","sourceRoot":"","sources":["../../src/inputs/yearPart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,oBAAY,YAAY;IACtB,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,QAAQ,aAAa;CACtB;AASD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,0FAA0F;IAC1F,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,IAAI,CAAC;CACf,CAAC;AA8BF,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAExD;AAED,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAEzD;AAED,iEAAiE;AACjE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,SAAU,GAAG,MAAM,CAE9E;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,SAAU,GAAG,MAAM,CAOxF;AAED,iEAAiE;AACjE,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,SAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAKxG;AAED,oCAAoC;AACpC,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,SAAU,GAAG,gBAAgB,CAuBxF;AAED,iGAAiG;AACjG,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,GAAG,aAAa,CAMxE"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recorte de um ano civil em fatias de tamanho igual: semestre (2), trimestre (4) e bimestre (6).
|
|
3
|
+
*
|
|
4
|
+
* Existe para o mesmo fim do SgPeriodSelector — resolver uma REGRA temporal para um intervalo real
|
|
5
|
+
* de datas — mas para a pergunta que ele nao responde: "o 1o semestre DE 2024", e nao "este
|
|
6
|
+
* semestre". Preset e' relativo a hoje; aqui o usuario escolhe ano e fatia.
|
|
7
|
+
*
|
|
8
|
+
* Modulo separado do componente porque isto e' aritmetica de calendario pura: da' para testar sem
|
|
9
|
+
* DOM (ver tests/year-part-resolver.test.mjs), que e' onde os erros de virada de mes/ano moram.
|
|
10
|
+
*/
|
|
11
|
+
export var YearPartKind;
|
|
12
|
+
(function (YearPartKind) {
|
|
13
|
+
YearPartKind["SEMESTER"] = "SEMESTER";
|
|
14
|
+
YearPartKind["QUARTER"] = "QUARTER";
|
|
15
|
+
YearPartKind["BIMESTER"] = "BIMESTER";
|
|
16
|
+
})(YearPartKind || (YearPartKind = {}));
|
|
17
|
+
/** Quantas fatias o ano tem em cada recorte. */
|
|
18
|
+
const PART_COUNT = {
|
|
19
|
+
[YearPartKind.SEMESTER]: 2,
|
|
20
|
+
[YearPartKind.QUARTER]: 4,
|
|
21
|
+
[YearPartKind.BIMESTER]: 6
|
|
22
|
+
};
|
|
23
|
+
/** Nome do recorte — e' o que aparece no combo que escolhe entre semestre/trimestre/bimestre. */
|
|
24
|
+
const KIND_LABELS = {
|
|
25
|
+
[YearPartKind.SEMESTER]: { "pt-BR": "Semestre", "en-US": "Half-year", es: "Semestre", "pt-PT": "Semestre", fr: "Semestre" },
|
|
26
|
+
[YearPartKind.QUARTER]: { "pt-BR": "Trimestre", "en-US": "Quarter", es: "Trimestre", "pt-PT": "Trimestre", fr: "Trimestre" },
|
|
27
|
+
[YearPartKind.BIMESTER]: { "pt-BR": "Bimestre", "en-US": "Bimester", es: "Bimestre", "pt-PT": "Bimestre", fr: "Bimestre" }
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Sigla da fatia, entre parenteses. NAO e' a inicial do nome traduzido: trimestre e' "Q" no
|
|
31
|
+
* portugues do Brasil e no ingles (Q1..Q4, vindo do business em ingles) mas "T" em espanhol,
|
|
32
|
+
* frances e portugues europeu, onde ninguem diz Q1. Bimestre nao tem sigla consagrada em lingua
|
|
33
|
+
* nenhuma — fica sem parenteses em vez de inventar uma.
|
|
34
|
+
*/
|
|
35
|
+
const PART_ABBR = {
|
|
36
|
+
[YearPartKind.SEMESTER]: { "pt-BR": "S", "en-US": "H", es: "S", "pt-PT": "S", fr: "S" },
|
|
37
|
+
[YearPartKind.QUARTER]: { "pt-BR": "Q", "en-US": "Q", es: "T", "pt-PT": "T", fr: "T" }
|
|
38
|
+
};
|
|
39
|
+
function pickLocale(map, locale) {
|
|
40
|
+
return map[locale] ?? map["pt-BR"] ?? Object.values(map)[0] ?? "";
|
|
41
|
+
}
|
|
42
|
+
/** Quantas fatias cabem no ano para este recorte. */
|
|
43
|
+
export function yearPartCount(kind) {
|
|
44
|
+
return PART_COUNT[kind];
|
|
45
|
+
}
|
|
46
|
+
/** Quantos meses tem cada fatia deste recorte: 6, 3 ou 2. */
|
|
47
|
+
export function yearPartMonths(kind) {
|
|
48
|
+
return 12 / PART_COUNT[kind];
|
|
49
|
+
}
|
|
50
|
+
/** Nome do recorte no locale pedido ("Trimestre", "Quarter"). */
|
|
51
|
+
export function yearPartKindLabel(kind, locale = "pt-BR") {
|
|
52
|
+
return pickLocale(KIND_LABELS[kind], locale);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Rotulo de uma fatia: "Trimestre 1 (Q1)", "Semestre 2 (S2)", "Bimestre 3".
|
|
56
|
+
*
|
|
57
|
+
* O numero vem DEPOIS do nome porque a forma ordinal ("1o trimestre") exigiria o indicador
|
|
58
|
+
* ordinal, que esta' fora do ASCII que esta familia de componentes usa nos rotulos.
|
|
59
|
+
*/
|
|
60
|
+
export function yearPartLabel(kind, part, locale = "pt-BR") {
|
|
61
|
+
const name = yearPartKindLabel(kind, locale);
|
|
62
|
+
const abbrMap = PART_ABBR[kind];
|
|
63
|
+
if (!abbrMap) {
|
|
64
|
+
return `${name} ${part}`;
|
|
65
|
+
}
|
|
66
|
+
return `${name} ${part} (${pickLocale(abbrMap, locale)}${part})`;
|
|
67
|
+
}
|
|
68
|
+
/** Opcoes prontas para o combo da fatia, ja no locale pedido. */
|
|
69
|
+
export function yearPartOptions(kind, locale = "pt-BR") {
|
|
70
|
+
return Array.from({ length: PART_COUNT[kind] }, (_, index) => ({
|
|
71
|
+
value: index + 1,
|
|
72
|
+
label: yearPartLabel(kind, index + 1, locale)
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
/** A fatia existe neste recorte? */
|
|
76
|
+
export function isValidYearPart(kind, part) {
|
|
77
|
+
return Number.isInteger(part) && part >= 1 && part <= PART_COUNT[kind];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Ao trocar o recorte, a fatia escolhida pode nao existir mais (estava no Q4 e virou semestre, que
|
|
81
|
+
* so' tem 2). Mantem a fatia quando ela couber, e cai na primeira quando nao couber — em vez de
|
|
82
|
+
* deixar um valor selecionado sem opcao correspondente na tela.
|
|
83
|
+
*/
|
|
84
|
+
export function clampYearPart(kind, part) {
|
|
85
|
+
return isValidYearPart(kind, part) ? part : 1;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Resolve o recorte para o intervalo fechado de datas.
|
|
89
|
+
*
|
|
90
|
+
* O ultimo dia sai de `new Date(ano, primeiroMesDaProximaFatia, 0)`: dia zero e' o ultimo dia do
|
|
91
|
+
* mes anterior, entao fevereiro devolve 29 em ano bissexto sem nenhuma tabela de dias por mes.
|
|
92
|
+
*
|
|
93
|
+
* Lanca quando a fatia nao existe no recorte — numero errado aqui vira intervalo errado no
|
|
94
|
+
* relatorio, e intervalo errado com cara de certo e' pior que erro na cara.
|
|
95
|
+
*/
|
|
96
|
+
export function resolveYearPart(value, locale = "pt-BR") {
|
|
97
|
+
const { year, kind, part } = value;
|
|
98
|
+
if (!Number.isInteger(year)) {
|
|
99
|
+
throw new RangeError(`Ano invalido: ${year}`);
|
|
100
|
+
}
|
|
101
|
+
if (!isValidYearPart(kind, part)) {
|
|
102
|
+
throw new RangeError(`Fatia ${part} nao existe em ${kind} (validas: 1..${PART_COUNT[kind]})`);
|
|
103
|
+
}
|
|
104
|
+
const months = yearPartMonths(kind);
|
|
105
|
+
const startMonth = (part - 1) * months;
|
|
106
|
+
return {
|
|
107
|
+
value: { year, kind, part },
|
|
108
|
+
label: yearPartLabel(kind, part, locale),
|
|
109
|
+
startDate: new Date(year, startMonth, 1, 0, 0, 0, 0),
|
|
110
|
+
// Dia zero do mes SEGUINTE a' fatia = ultimo dia da fatia, e fevereiro devolve 29 em ano
|
|
111
|
+
// bissexto sem nenhuma tabela de dias por mes. Fecha em 23:59:59.999 como o resolvePeriod:
|
|
112
|
+
// intervalo que termina a' meia-noite perde o ultimo dia inteiro num BETWEEN com hora.
|
|
113
|
+
endDate: new Date(year, startMonth + months, 0, 23, 59, 59, 999)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/** Em que fatia do recorte esta data cai. Util para posicionar o seletor no periodo corrente. */
|
|
117
|
+
export function yearPartOf(date, kind) {
|
|
118
|
+
return {
|
|
119
|
+
year: date.getFullYear(),
|
|
120
|
+
kind,
|
|
121
|
+
part: Math.floor(date.getMonth() / yearPartMonths(kind)) + 1
|
|
122
|
+
};
|
|
123
|
+
}
|